Jump to content
Sign in to follow this  
WideBoyDixon

Drag-and-drop reordering listbox

Recommended Posts

WideBoyDixon

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

Share this post


Link to post
Share on other sites
UEZ

Nice code example! Well done again!

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
xeroTechnologiesLLC

I like, only difficulty I am finding is that it doesn't shut down correctly - seems to crash.

I appreciate the hard work done on this code all the same.

I'm working a project that this will be invaluable!

+1

Share this post


Link to post
Share on other sites
Spenhouet

I used ure code but... where is $GWL_WNDPROC declared?

Share this post


Link to post
Share on other sites
UEZ

Global Const $GWL_WNDPROC = 0xFFFFFFFC (see Constants.au3).

Br,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
Spenhouet

ah thx.

But i have to use this:

because of ListView.

Thx to Melba in this case ;)

Share this post


Link to post
Share on other sites
Belini
iCode

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)

Share this post


Link to post
Share on other sites
LarsJ

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
Sign in to follow this  

×