Jump to content

Drag-and-drop reordering listbox


 Share

Recommended Posts

I had a quick look around and couldn't find this anywhere so I'm posting up some code. This allows you to drag-and-drop the items in the listbox in order to reorder them. A nice UI touch when you want users to have the ability to do this. I'm writing something right now that will use this but thought I'd put this code here in case someone wants to use it.

#include <Constants.au3>
#include <GUIListBox.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

Global $gnDRAGLISTMSGSTRING = _WinAPI_RegisterWindowMessage("commctrl_DragListMsg")
Global $DL_BEGINDRAG = $WM_USER + 133
Global $DL_DRAGGING = $WM_USER + 134
Global $DL_DROPPED = $WM_USER + 135
Global $DL_CANCELDRAG = $WM_USER + 136
Global Enum $DL_STOPCURSOR = 1, $DL_COPYCURSOR, $DL_MOVECURSOR
Global $gtDRAGLISTINFO = "long uNotification;long hWnd;long x;long y"
Global $gfItemAdded = False

Global $hMain = GUICreate("DragList", 200, 400)
Global $cListbox = GUICtrlCreateList("", 16, 16, 168, 368, $WS_BORDER + $WS_VSCROLL)
GUICtrlSetFont($cListbox, 10, Default, Default, "Tahoma")
Global $hListbox = GUICtrlGetHandle($cListbox)
GUICtrlSetData($cListbox, "Apples|Oranges|Bananas|Pears|Grapefruits|Limes|Lemons|Strawberries|Plums|Melons|Grapes|")
GUISetState()

_ComCtl32_MakeDragList($hListbox)

Global $wProcNew = DllCallbackRegister("_MyWndProc", "int", "hwnd;int;wparam;lparam")
Global $wProcOld = _WinAPI_SetWindowLong($hMain, $GWL_WNDPROC, DllCallbackGetPtr($wProcNew))

While GUIGetMsg() <> -3
    Sleep(10)
Wend

Exit

Func _MyWndProc($hWnd, $nMsg, $wParam, $lParam)
    Local $aRet, $nOldIndex, $sItemText
    If $nMsg = $gnDRAGLISTMSGSTRING Then
        Local $tDRAGLISTINFO = DllStructCreate($gtDRAGLISTINFO, $lParam)
        Local $uNotification = DllStructGetData($tDRAGLISTINFO, "uNotification")
        Local $x = DllStructGetData($tDRAGLISTINFO, "x"), $y = DllStructGetData($tDRAGLISTINFO, "y")
        Local $nItem = _ComCtl32_LBItemFromPt($hListbox, $x, $y)
        Switch $uNotification
            Case $DL_BEGINDRAG
                If $nItem < (_GUICtrlListBox_GetCount($hListbox) - 1) Then
                    _GUICtrlListBox_AddString($hListbox, "")
                    $gfItemAdded = True
                EndIf
                Return 1
            Case $DL_DRAGGING
                _ComCtl32_DrawInsert($hMain, $hListbox, $nItem)
                If $nItem = _GUICtrlListBox_GetCurSel($hListbox) Then Return $DL_STOPCURSOR
                Return $DL_MOVECURSOR
            Case $DL_DROPPED
                If $nItem > -1 Then
                    $nOldIndex = _GUICtrlListBox_GetCurSel($hListbox)
                    If $nItem <> $nOldIndex Then
                        $sItemText = _GUICtrlListBox_GetText($hListbox, $nOldIndex)
                        If $nItem < $nOldIndex Then $nOldIndex += 1
                        _GUICtrlListBox_InsertString($hListbox, $sItemText, $nItem)
                        _GUICtrlListBox_DeleteString($hListbox, $nOldIndex)
                        If $nItem > $nOldIndex Then $nItem -= 1
                        _GUICtrlListBox_SetCurSel($hListbox, $nItem)
                    EndIf
                EndIf
                If $gfItemAdded Then
                    _GUICtrlListBox_DeleteString($hListbox, _GUICtrlListBox_GetCount($hListbox) - 1)
                    $gfItemAdded = False
                EndIF
                _ComCtl32_DrawInsert($hMain, $hListbox, -1)
                Return 0
            Case $DL_CANCELDRAG
                If $gfItemAdded Then
                    _GUICtrlListBox_DeleteString($hListbox, _GUICtrlListBox_GetCount($hListbox) - 1)
                    $gfItemAdded = False
                EndIF
                _ComCtl32_DrawInsert($hMain, $hListbox, -1)
                Return 0
        EndSwitch
    EndIf
    Return _WinAPI_CallWindowProc($wProcOld, $hWnd, $nMsg, $wParam, $lParam)
EndFunc

Func _ComCtl32_MakeDragList($hWnd)
    Local $aRet = DllCall("comctl32.dll", "int", "MakeDragList", "hwnd", $hWnd)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aRet[0]
EndFunc

Func _ComCtl32_LBItemFromPt($hWnd, $x, $y)
    Local $aRet = DllCall("comctl32.dll", "long", "LBItemFromPt", "hwnd", $hWnd, "long", $x, "long", $y, "long", 1)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aRet[0]
EndFunc

Func _ComCtl32_DrawInsert($hWndParent, $hWnd, $nItem)
    DllCall("comctl32.dll", "none", "DrawInsert", "hwnd", $hWndParent, "hwnd", $hWnd, "long", $nItem)
    If @error Then Return SetError(@error, @extended, 0)
    Return
EndFunc

Enjoy.

WBD

Link to comment
Share on other sites

  • 2 years later...
  • 1 month later...
Link to comment
Share on other sites

  • 1 year later...

Anybody else having a problem where this example script fails to exit (and hogs the CPU)? It works fine other than that, but i'm not good at all in troubleshooting dll issues, which i suspect is the cause. Using DllOpen/DllClose and using the handle in the functions doesn't solve the problem, nor does compiling it, and there is no Scite error code on exit when the process is killed.

FUNCTIONS: WinDock (dock window to screen edge) | EditCtrl_ToggleLineWrap (line/word wrap for AU3 edit control) | SendEX (yet another alternative to Send( ) ) | Spell Checker (Hunspell wrapper) | SentenceCase (capitalize first letter of sentences)

CODE SNIPPITS: Dynamic tab width (set tab control width according to window width)

Link to comment
Share on other sites

Just restore the old window procedure immediately before the Exit command:

 

_WinAPI_SetWindowLong($hMain, $GWL_WNDPROC, DllCallbackGetPtr($wProcOld))
Link to comment
Share on other sites

thanks LarsJ - works fine!

FUNCTIONS: WinDock (dock window to screen edge) | EditCtrl_ToggleLineWrap (line/word wrap for AU3 edit control) | SendEX (yet another alternative to Send( ) ) | Spell Checker (Hunspell wrapper) | SentenceCase (capitalize first letter of sentences)

CODE SNIPPITS: Dynamic tab width (set tab control width according to window width)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...