Drag and drop in listbox
Drag and drop in listbox
Is it possible to react to the use of drag and drop in a listbox to move the items?
- divanebaba
- Posts: 816
- Joined: 20 Dec 2016, 03:53
- Location: Diaspora
Re: Drag and drop in listbox
If I had understand you the right way, i can say it is possible by using A_GuiControl, which contains text or the name of the control, you dropped the files on.
See this example executing the if-statement and messaging the name of the variable when you drop any file onto the listbox.
See this example executing the if-statement and messaging the name of the variable when you drop any file onto the listbox.
Code: Select all
gui, add, listbox, vMyListBox
gui, show, w200 h200
return
GuiDropFiles:
if (A_GuiControl = "MyListBox")
msgbox % A_GuiControl
return
Einfach nur ein toller Typ.
-
- Posts: 4393
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Drag and drop in listbox
Proof of concept:
Code: Select all
#NoEnv
SetBatchLines, -1
Gui, Font, s12
Gui, Add, ListBox, r5 w200 hwndhLB, Drag me!|Item 2|Item 3|Item 4|Item 5
Gui, Show
Hook := new WindowsHook(WH_MOUSE_LL := 14, "LowLevelMouseProc", hLB)
Return
GuiClose() {
ExitApp
}
LowLevelMouseProc(nCode, wParam, lParam) {
static WM_MOUSEMOVE := 0x200, WM_LBUTTONDOWN := 0x201, WM_LBUTTONUP := 0x202
, hListBox, items, captured, viewInfo, startX, startY
(!hListBox && hListBox := A_EventInfo)
if (wParam = WM_LBUTTONDOWN) {
MouseGetPos,,,, hCtrl, 2
if (hCtrl = hListBox)
items := MapItems(hListBox, lParam, captured, startX, startY)
}
if (wParam = WM_MOUSEMOVE && captured) {
viewInfo := CreateView(items, captured)
captured := ""
}
if (wParam = WM_MOUSEMOVE && viewInfo) {
MoveView(lParam, viewInfo, startX, startY)
}
if (wParam = WM_LBUTTONUP && !(captured := "") && viewInfo) {
InsertItem(hListBox, lParam, items, viewInfo)
viewInfo := ""
Send, {LButton Up}
}
Return DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "Ptr", wParam, "Ptr", lParam)
}
MapItems(hListBox, pMouseData, ByRef captured, ByRef startX, ByRef startY) {
static LB_GETCOUNT := 0x18B, LB_GETITEMRECT := 0x198
point := CreatePoint(hListBox, pMouseData, ctrlX, ctrlY, startX, startY)
items := []
SendMessage, LB_GETCOUNT,,,, ahk_id %hListBox%
Loop % ErrorLevel {
items.SetCapacity(A_Index, 16), pRECT := items.GetAddress(A_Index)
SendMessage, LB_GETITEMRECT, A_Index - 1, pRECT,, ahk_id %hListBox%
if DllCall("PtInRect", "Ptr", pRECT, "UInt64", point)
captured := {item: A_Index, ctrlX: ctrlX, ctrlY: ctrlY}
}
Return items
}
CreateView(items, captured) {
pRECT := items.GetAddress(captured.item)
itemLeft := NumGet(pRECT + 0, "Int")
itemTop := NumGet(pRECT + 4, "Int")
itemRight := NumGet(pRECT + 8, "Int")
itemBottom := NumGet(pRECT + 12, "Int")
viewX := captured.ctrlX + itemLeft + 2
viewY := captured.ctrlY + itemTop + 2
viewWidth := itemRight - itemLeft
viewHeight := itemBottom - itemTop
hDC := DllCall("GetDC", "Ptr", 0, "Ptr")
hBM := DllCall("CreateCompatibleBitmap", "Ptr", hDC, "Int", viewWidth, "Int", viewHeight, "Ptr")
hMDC := DllCall("CreateCompatibleDC", "Ptr", hDC, "Ptr")
hObj := DllCall("SelectObject", "Ptr", hMDC, "Ptr", hBM)
DllCall("BitBlt", "Ptr", hMDC, "Int", 0, "Int", 0, "Int", viewWidth, "Int", viewHeight
, "Ptr", hDC, "Int", viewX, "Int", viewY, "UInt", SRCCOPY := 0xCC0020)
DllCall("SelectObject", "Ptr", hMDC, "Ptr", hObj)
DllCall("DeleteDC", "Ptr", hMDC)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
Gui, New, -Caption +AlwaysOnTop +Owner +hwndhGui
Gui, Margin, 0, 0
Gui, Add, Pic,, HBITMAP:%hBM%
Gui, Show, x%viewX% y%viewY% NA
Return {hwnd: hGui, x: viewX, y: viewY, item: captured.item}
}
MoveView(pMouseData, viewInfo, startX, startY) {
mouseX := NumGet(pMouseData + 0, "Int"), mouseY := NumGet(pMouseData + 4, "Int")
Gui, % viewInfo.hwnd . ":Show", % "NA x" . mouseX - startX + viewInfo.x
. " y" . mouseY - startY + viewInfo.y
}
InsertItem(hListBox, pMouseData, items, viewInfo) {
Gui, % viewInfo.hwnd . ":Destroy"
itemIdx := viewInfo.item
point := CreatePoint(hListBox, pMouseData)
ControlGet, list, List,,, ahk_id %hListBox%
itemsText := StrSplit(list, "`n")
Loop % items.Length() {
i := A_Index
if ( i = itemIdx || !DllCall("PtInRect", "Ptr", items.GetAddress(i), "UInt64", point) )
continue
b := i > itemIdx
itemsText.InsertAt(i + b, itemsText[itemIdx])
itemsText.RemoveAt(itemIdx + !b)
for k, v in itemsText
text .= "|" . v . (k = i ? "|" : "")
GuiControl,, %hListBox%, % RegExReplace(text, "\|$", "||")
break
}
}
CreatePoint(hWnd, pMouseData, ByRef X := "", ByRef Y := "", ByRef mouseX := "", ByRef mouseY := "") {
WinGetPos, X, Y,,, ahk_id %hWnd%
mouseX := NumGet(pMouseData + 0, "Int") - 2
mouseY := NumGet(pMouseData + 4, "Int") - 2
Return mouseX - X | (mouseY - Y) << 32
}
class WindowsHook {
__New(type, callback, eventInfo := "", isGlobal := true) {
this.pCallback := RegisterCallback(callback, "Fast", 3, eventInfo)
this.hHook := DllCall("SetWindowsHookEx", "Int", type, "Ptr", this.pCallback
, "Ptr", !isGlobal ? 0 : DllCall("GetModuleHandle", "UInt", 0, "Ptr")
, "UInt", isGlobal ? 0 : DllCall("GetCurrentThreadId"), "Ptr")
}
__Delete() {
DllCall("UnhookWindowsHookEx", "Ptr", this.hHook)
DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
}
}
Last edited by teadrinker on 24 Jun 2020, 11:59, edited 1 time in total.
Re: Drag and drop in listbox
Thank you for your answers, I will try the code tomorrow.
@teadrinker
That code looks aweful! Did not know such things are possible within ahk. I will need some time to understand what you are doing.
@teadrinker
That code looks aweful! Did not know such things are possible within ahk. I will need some time to understand what you are doing.
-
- Posts: 4393
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Drag and drop in listbox
Feel free to ask questions.
Re: Drag and drop in listbox
Thank you for your answer, though it does not address my question. I don't want to drag file names from another program, I want to use drag and drop for moving items within the list. Teadrinkers code works perfectly well for me.divanebaba
Thank you for your code, it works perfectly.Teadrinker
Still, I would like to fully understand what it does, and I have several questions (maybe more to come )
1.
Code: Select all
new WindowsHook
2.
Code: Select all
static WM_MOUSEMOVE := 0x200, WM_LBUTTONDOWN := 0x201, WM_LBUTTONUP := 0x202
, LB_GETCOUNT := 0x18B, LB_GETITEMRECT := 0x198
3.
Code: Select all
(!hLB && hLB := A_EventInfo)
-
- Posts: 4393
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Drag and drop in listbox
- Some links:
new
Custom Objects
Construction and DestructionBy this way the new instance of WindowsHook class is created and the __New() method is called. In this method winapi SetWindowsHookEx is called with the WH_MOUSE_LL hook type. This hook passes all mouse events through LowLevelMouseProc() function. - Google them like this: #define WM_MOUSEMOVE
- This is the same as
Code: Select all
if !hLB { hLB := A_EventInfo }
-
- Posts: 4393
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Drag and drop in listbox
I've redesigned the script to have it more clear.
Re: Drag and drop in listbox
Thank you for your help!
1. Thats a lot of links to read. I was not aware that there is much more online help than in the chm-file that I have been using until now as documentation.
2. ok, as I thought, a lot of constants for a lot of purposes...
3. This is VICIOUS Even after your explanation, it took me quite a while to figure out how that works and why that works - using an assignment within an expression, using the fact that AHK short-circuits the evaluation of boolean expressions, and discarding the result of the expression...
Is that common practice to reduce the line count of the script by 1, or does it increase execution speed?
-
- Posts: 4393
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Drag and drop in listbox
No, online help and the chm-file should be identical. Make sure that your chm is latest.
I'm not sure that it's common practice, some people consider that bad practice. I like using it to save place, if it doesn't impair readability.
Re: Drag and drop in listbox
Why not make use of the standard ListBox control notifications for this? https://docs.microsoft.com/en-us/windows/win32/controls/dl-begindrag
Also, https://docs.microsoft.com/en-us/windows/win32/controls/about-list-boxes#drag-list-boxes
Also, https://docs.microsoft.com/en-us/windows/win32/controls/about-list-boxes#drag-list-boxes
-
- Posts: 4393
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Drag and drop in listbox
This can be used, but this doesn't simplify the task, since for some reason doesn't send the DL_DRAGGING notification, and you need to track cursor moving in any way to move an item picture.
Code: Select all
#NoEnv
SetBatchLines, -1
Gui, Font, s12
Gui, Add, ListBox, r5 w200 hwndhLB, Drag me!|Item 2|Item 3|Item 4|Item 5
DllCall("MakeDragList", "Ptr", hLB)
Gui, Show
DRAGLISTMSGSTRING := "commctrl_DragListMsg"
msg := DllCall("RegisterWindowMessage", "Str", DRAGLISTMSGSTRING)
OnMessage(msg, "OnDrag")
Return
GuiClose() {
ExitApp
}
OnDrag(wp, lp) {
static DL_BEGINDRAG := 1157, DL_DRAGGING := 1158, DL_DROPPED := 1159, DL_CANCELDRAG := 1160
ToolTip % NumGet(lp + 0, "UInt")
}
-
- Posts: 4393
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Drag and drop in listbox
Can't get what is the issue. However, using LBItemFromPt gives some simplification:
Code: Select all
#NoEnv
SetBatchLines, -1
Gui, Font, s12
Gui, Add, ListBox, r5 w200 hwndhLB, Drag me!|Item 2|Item 3|Item 4|Item 5
DllCall("MakeDragList", "Ptr", hLB)
Gui, Show
DRAGLISTMSGSTRING := "commctrl_DragListMsg"
msg := DllCall("RegisterWindowMessage", "Str", DRAGLISTMSGSTRING)
OnMessage(msg, "OnDrag")
Return
GuiClose() {
ExitApp
}
OnDrag(wp, lp) {
static DL_BEGINDRAG := 1157, DL_DROPPED := 1159, DL_CANCELDRAG := 1160
, WH_MOUSE_LL := 14, viewInfo, pViewInfo, Hook
ntf := NumGet(lp + 0, "UInt")
hListBox := NumGet(lp + A_PtrSize)
POINT := NumGet(lp + A_PtrSize*2, "UInt64")
item := DllCall("LBItemFromPt", "Ptr", hListBox, "UInt64", POINT, "UInt", true)
if (ntf = DL_BEGINDRAG) {
captured := GetCapturedItem(hListBox, POINT, item)
viewInfo := CreateView(captured)
pViewInfo := Object(viewInfo)
Hook := new WindowsHook(WH_MOUSE_LL, "LowLevelMouseProc", pViewInfo)
}
if (ntf = DL_DROPPED || ntf = DL_CANCELDRAG) {
Hook := ""
InsertItem(hListBox, item, viewInfo)
ObjRelease(pViewInfo), viewInfo := ""
}
}
GetCapturedItem(hListBox, POINT, idx) {
item := {idx: idx, hCtrl: hListBox}
item.SetCapacity("RECT", 16), pRECT := item.GetAddress("RECT")
SendMessage, LB_GETITEMRECT := 0x198, idx, pRECT,, ahk_id %hListBox%
WinGetPos, X, Y,,, ahk_id %hListBox%
item.ctrlX := X, item.ctrlY := Y
item.startX := POINT & 0xFFFFFFFF, item.startY := POINT >> 32
Return item
}
CreateView(captured) {
pRECT := captured.GetAddress("RECT")
itemLeft := NumGet(pRECT + 0, "Int")
itemTop := NumGet(pRECT + 4, "Int")
itemRight := NumGet(pRECT + 8, "Int")
itemBottom := NumGet(pRECT + 12, "Int")
viewX := captured.ctrlX + itemLeft + 2
viewY := captured.ctrlY + itemTop + 2
viewWidth := itemRight - itemLeft
viewHeight := itemBottom - itemTop
hDC := DllCall("GetDC", "Ptr", 0, "Ptr")
hBM := DllCall("CreateCompatibleBitmap", "Ptr", hDC, "Int", viewWidth, "Int", viewHeight, "Ptr")
hMDC := DllCall("CreateCompatibleDC", "Ptr", hDC, "Ptr")
hObj := DllCall("SelectObject", "Ptr", hMDC, "Ptr", hBM)
DllCall("BitBlt", "Ptr", hMDC, "Int", 0, "Int", 0, "Int", viewWidth, "Int", viewHeight
, "Ptr", hDC, "Int", viewX, "Int", viewY, "UInt", SRCCOPY := 0xCC0020)
DllCall("SelectObject", "Ptr", hMDC, "Ptr", hObj)
DllCall("DeleteDC", "Ptr", hMDC)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
Gui, New, -Caption +AlwaysOnTop +Owner +hwndhGui
Gui, Margin, 0, 0
Gui, Add, Pic,, HBITMAP:%hBM%
Gui, Show, x%viewX% y%viewY% NA
Return {hwnd: hGui, hCtrl: captured.hCtrl, x: captured.startX - viewX, y: captured.startY - viewY, item: captured.idx}
}
InsertItem(hListBox, targetIdx, viewInfo) {
static LB_INSERTSTRING := 0x181, LB_DELETESTRING := 0x182, LB_SETCURSEL := 0x186
Gui, % viewInfo.hwnd . ":Destroy"
itemIdx := viewInfo.item
if (targetIdx = itemIdx || targetIdx = -1)
Return
ControlGet, list, List,,, ahk_id %hListBox%
itemText := StrSplit(list, "`n")[itemIdx + 1]
SendMessage, LB_DELETESTRING, itemIdx,,, ahk_id %hListBox%
SendMessage, LB_INSERTSTRING, targetIdx, &itemText,, ahk_id %hListBox%
SendMessage, LB_SETCURSEL, targetIdx,,, ahk_id %hListBox%
}
LowLevelMouseProc(nCode, wParam, lParam) {
static WM_MOUSEMOVE := 0x200, LB_SETCURSEL := 0x186, prevItem
if (wParam = WM_MOUSEMOVE) {
viewInfo := Object(A_EventInfo)
mouseX := NumGet(lParam + 0, "Int"), mouseY := NumGet(lParam + 4, "Int")
Gui, % viewInfo.hwnd . ":Show", % "NA x" . mouseX - viewInfo.x
. " y" . mouseY - viewInfo.y
POINT := mouseX | mouseY << 32
item := DllCall("LBItemFromPt", "Ptr", viewInfo.hCtrl, "UInt64", POINT, "UInt", true)
if (item != prevItem) {
prevItem := item
SendMessage, LB_SETCURSEL, item,,, % "ahk_id" . viewInfo.hCtrl
}
}
Return DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "Ptr", wParam, "Ptr", lParam)
}
class WindowsHook {
__New(type, callback, eventInfo := "", isGlobal := true) {
this.pCallback := RegisterCallback(callback, "Fast", 3, eventInfo)
this.hHook := DllCall("SetWindowsHookEx", "Int", type, "Ptr", this.pCallback
, "Ptr", !isGlobal ? 0 : DllCall("GetModuleHandle", "UInt", 0, "Ptr")
, "UInt", isGlobal ? 0 : DllCall("GetCurrentThreadId"), "Ptr")
}
__Delete() {
DllCall("UnhookWindowsHookEx", "Ptr", this.hHook)
DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
}
}
-
- Posts: 4393
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Drag and drop in listbox
That's better:
Code: Select all
#NoEnv
SetBatchLines, -1
Gui, Font, s12
Gui, Add, ListBox, r5 w200 hwndhLB, Drag me!|Item 2|Item 3|Item 4|Item 5
DllCall("MakeDragList", "Ptr", hLB)
Gui, Show
DRAGLISTMSGSTRING := "commctrl_DragListMsg"
msg := DllCall("RegisterWindowMessage", "Str", DRAGLISTMSGSTRING)
OnMessage(msg, "OnDrag")
Return
GuiClose() {
ExitApp
}
OnDrag(wp, lp) {
static DL_BEGINDRAG := 1157, DL_DROPPED := 1159, DL_CANCELDRAG := 1160
, WH_MOUSE_LL := 14, viewInfo, pViewInfo, Hook
ntf := NumGet(lp + 0, "UInt")
hListBox := NumGet(lp + A_PtrSize)
POINT := NumGet(lp + A_PtrSize*2, "UInt64")
item := DllCall("LBItemFromPt", "Ptr", hListBox, "UInt64", POINT, "UInt", true)
if (ntf = DL_BEGINDRAG) {
captured := GetCapturedItem(hListBox, POINT, item)
viewInfo := CreateView(captured)
pViewInfo := Object(viewInfo)
Hook := new WindowsHook(WH_MOUSE_LL, "LowLevelMouseProc", pViewInfo)
}
if (ntf = DL_DROPPED || ntf = DL_CANCELDRAG) {
Hook := ""
Gui, % viewInfo.hwnd . ":Destroy"
ObjRelease(pViewInfo), viewInfo := ""
}
}
GetCapturedItem(hListBox, POINT, idx) {
item := {idx: idx, hCtrl: hListBox}
item.SetCapacity("RECT", 16), pRECT := item.GetAddress("RECT")
SendMessage, LB_GETITEMRECT := 0x198, idx, pRECT,, ahk_id %hListBox%
WinGetPos, X, Y,,, ahk_id %hListBox%
item.ctrlX := X, item.ctrlY := Y
item.startX := POINT & 0xFFFFFFFF, item.startY := POINT >> 32
Return item
}
CreateView(captured) {
pRECT := captured.GetAddress("RECT")
itemLeft := NumGet(pRECT + 0, "Int")
itemTop := NumGet(pRECT + 4, "Int")
itemRight := NumGet(pRECT + 8, "Int")
itemBottom := NumGet(pRECT + 12, "Int")
viewX := captured.ctrlX + itemLeft + 2
viewY := captured.ctrlY + itemTop + 2
viewWidth := itemRight - itemLeft
viewHeight := itemBottom - itemTop
hDC := DllCall("GetDC", "Ptr", 0, "Ptr")
hBM := DllCall("CreateCompatibleBitmap", "Ptr", hDC, "Int", viewWidth, "Int", viewHeight, "Ptr")
hMDC := DllCall("CreateCompatibleDC", "Ptr", hDC, "Ptr")
hObj := DllCall("SelectObject", "Ptr", hMDC, "Ptr", hBM)
DllCall("BitBlt", "Ptr", hMDC, "Int", 0, "Int", 0, "Int", viewWidth, "Int", viewHeight
, "Ptr", hDC, "Int", viewX, "Int", viewY, "UInt", SRCCOPY := 0xCC0020)
DllCall("SelectObject", "Ptr", hMDC, "Ptr", hObj)
DllCall("DeleteDC", "Ptr", hMDC)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
Gui, New, -Caption +AlwaysOnTop +Owner +hwndhGui
Gui, Margin, 0, 0
Gui, Add, Pic,, HBITMAP:%hBM%
Gui, Show, x%viewX% y%viewY% NA
ControlGet, list, List,,, % "ahk_id" . captured.hCtrl
Return { hwnd: hGui, hCtrl: captured.hCtrl
, item: captured.idx, text: StrSplit(list, "`n")[captured.idx + 1]
, x: captured.startX - viewX, y: captured.startY - viewY }
}
LowLevelMouseProc(nCode, wParam, lParam) {
static WM_MOUSEMOVE := 0x200, LB_INSERTSTRING := 0x181, LB_DELETESTRING := 0x182, LB_SETCURSEL := 0x186
if (wParam = WM_MOUSEMOVE) {
viewInfo := Object(A_EventInfo)
(viewInfo.prevItem = "" && viewInfo.prevItem := viewInfo.item)
mouseX := NumGet(lParam + 0, "Int"), mouseY := NumGet(lParam + 4, "Int")
Gui, % viewInfo.hwnd . ":Show", % "NA x" . mouseX - viewInfo.x
. " y" . mouseY - viewInfo.y
POINT := mouseX | mouseY << 32
item := DllCall("LBItemFromPt", "Ptr", viewInfo.hCtrl, "UInt64", POINT, "UInt", true)
if !(item = viewInfo.prevItem || item = -1) {
SendMessage, LB_DELETESTRING, viewInfo.prevItem,,, % "ahk_id" . viewInfo.hCtrl
SendMessage, LB_INSERTSTRING, item, viewInfo.GetAddress("text"),, % "ahk_id" . viewInfo.hCtrl
SendMessage, LB_SETCURSEL, item,,, % "ahk_id" . viewInfo.hCtrl
viewInfo.prevItem := item
}
}
Return DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "Ptr", wParam, "Ptr", lParam)
}
class WindowsHook {
__New(type, callback, eventInfo := "", isGlobal := true) {
this.pCallback := RegisterCallback(callback, "Fast", 3, eventInfo)
this.hHook := DllCall("SetWindowsHookEx", "Int", type, "Ptr", this.pCallback
, "Ptr", !isGlobal ? 0 : DllCall("GetModuleHandle", "UInt", 0, "Ptr")
, "UInt", isGlobal ? 0 : DllCall("GetCurrentThreadId"), "Ptr")
}
__Delete() {
DllCall("UnhookWindowsHookEx", "Ptr", this.hHook)
DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
}
}
Re: Drag and drop in listbox
@teadrinker that's pretty slick!
This is how I'd have done it probably (I use AHK v2). Thanks to your help on some of the early parts of the code. Is the value of DRAGLISTMSGSTRING anything special or is it random? Also, you weren't getting DL_DRAGGING because you're not returning true when ntf = DL_BEGINDRAG.
This is how I'd have done it probably (I use AHK v2). Thanks to your help on some of the early parts of the code. Is the value of DRAGLISTMSGSTRING anything special or is it random? Also, you weren't getting DL_DRAGGING because you're not returning true when ntf = DL_BEGINDRAG.
Code: Select all
main := Gui.new()
main.setFont("S10", "Tahoma")
main.onevent("close", (*) => ExitApp())
lb := main.add("Listbox", "r5", ["item 1", "thing 2", "stuff 3", "horse 4", "straw 5"])
DllCall("MakeDragList", "Ptr", lb.hwnd, "Int")
DRAGLISTMSGSTRING := "commctrl_DragListMsg"
msg := DllCall("RegisterWindowMessage", "Str", DRAGLISTMSGSTRING)
OnMessage(msg, "OnDrag")
main.show()
OnDrag(w, l, msg, hwnd) {
static DL_BEGINDRAG := 1157, DL_DRAGGING := 1158, DL_DROPPED := 1159, DL_CANCELDRAG := 1160, dragItem := false
ntf := NumGet(l + 0, "UInt")
hListBox := NumGet(l, A_PtrSize)
POINT := NumGet(l, A_PtrSize*2, "UInt64")
item := DllCall("LBItemFromPt", "Ptr", hListBox, "UInt64", POINT, "UInt", true, "Int")
Switch (ntf) {
case DL_BEGINDRAG:
dragItem := item
return True ; must return true here otherwise you won't get DL_DRAGGING
case DL_DRAGGING:
drawInsert(item)
case DL_DROPPED:
drawInsert(-1)
if (dragItem != item) {
moveItem()
}
case DL_CANCELDRAG:
drawInsert(-1)
}
drawInsert(relativeItem) {
DllCall("DrawInsert", "Ptr", hwnd, "Ptr", hListBox, "Int", relativeItem)
}
moveItem() {
static LB_INSERTSTRING := 0x181
ctrl := GuiCtrlFromHwnd(hListbox)
; get the text of the currently selected item and delete it
selectedText := ctrl.text
ctrl.Delete(dragItem + 1)
; don't think the guictrl object gives a way to insert at an arbitrary position so use DllCall
SendMessage(LB_INSERTSTRING, item, StrPtr(selectedText), hListbox)
; setting the value for a ListBox ultimately changes the selected item
ctrl.value := item + 1
}
}
-
- Posts: 4393
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Drag and drop in listbox
-
- Posts: 4393
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Drag and drop in listbox
@kczx3
Mouse Hook vs DL_DRAGGING
DL_DRAGGING starts to be sent only when the cursor leaves an dragged element, and a slight lag occurs.Re: Drag and drop in listbox
I think it’s just a matter of preference and complexity. I think the built-in notification is sufficient enough and I prefer to use methods provided by Microsoft whenever possible. I think changing the cursor at BEGINDRAG would help to convey a drag operation is possible