引入
在ahk v1中ListView有事件"D"代表拖拽开始,进而对拖拽事件进行处理。
可参考:Github Pulover- Class_LV_Rows 该v1类库就据此实现了Drag拖拽特效。
但v2中ListView的"D"事件没有被官方实现,必须自己使用"OnNotify()"进行实现,此外 Class_LV_Rows 类库也仅仅提供了v1版本。
本人将其中的"LV_Drag()"方法用v2实现,并给出"D"事件的实现方式。
可以实现很多不错的功能:
- 拖动排序
- 从一个列表拖动项目到另一个列表
- 拖动到列表外删除项目
基础示例
g := Gui()
LV := g.Add("ListView", "x10 y10 w500 h500", ["No", "foo"])
loop 30
LV.Add(, A_Index, "bar" A_Index)
LV.ModifyCol(1, "AutoHdr"), LV.ModifyCol(2, "AutoHdr")
g.Show()
LVN_BEGINDRAG := -109
LV.OnNotify(LVN_BEGINDRAG, LV_OnDrag) ; 接受拖动事件通知
LV_OnDrag(LV, lParam) {
; NMHDR_hwndFrom := NumGet(lParam, 0, 'Ptr')
; NMHDR_idFrom := NumGet(lParam, A_PtrSize, 'UInt')
; NMHDR_code := NumGet(lParam, 2 * A_PtrSize, 'UInt')
; NMLISTVIEW_iItem := NumGet(lParam, 3 * A_PtrSize, 'Int') ; The begin row num (from 1).
beginRowNum := NumGet(lParam, 3 * A_PtrSize, 'Int') + 1 ; 通知消息中解析出拖动开始的行号
endRowNum := LV_Drag() ; 显示拖动横条,直到拖动结束返回最终行号,超出范围返回""
ToolTip(Format("{}-{}", beginRowNum, endRowNum))
}
函数实现
LV_Drag.ah2
/**
* @Name: LV_Drag
* @Author: ruchuby
* @LastEditors: ruchuby
* @LastEditTime: 2023-03-16
* @Description: 拖拽事件触发时调用LV_Drag,显示拖动横条并在拖动结束时返回最终行号
* Update from Pulover [Rodolfo U. Batista]'s Class_LV_Rows: https://github.com/Pulover/Class_LV_Rows/blob/master/Class_LV_Rows.ahk
*/
;example
/*
g := Gui()
LV := g.Add("ListView", "x10 y10 w500 h500", ["No", "foo"])
loop 30
LV.Add(, A_Index, "bar" A_Index)
LV.ModifyCol(1, "AutoHdr"), LV.ModifyCol(2, "AutoHdr")
g.Show()
LVN_BEGINDRAG := -109
LV.OnNotify(LVN_BEGINDRAG, LV_OnDrag) ; 接受拖动事件通知
LV_OnDrag(LV, lParam) {
; NMHDR_hwndFrom := NumGet(lParam, 0, 'Ptr')
; NMHDR_idFrom := NumGet(lParam, A_PtrSize, 'UInt')
; NMHDR_code := NumGet(lParam, 2 * A_PtrSize, 'UInt')
; NMLISTVIEW_iItem := NumGet(lParam, 3 * A_PtrSize, 'Int') ; The begin row num (from 1).
beginRowNum := NumGet(lParam, 3 * A_PtrSize, 'Int') + 1 ; 通知消息中解析出拖动开始的行号
endRowNum := LV_Drag() ; 显示拖动横条,直到拖动结束返回最终行号,超出范围返回""
ToolTip(Format("{}-{}", beginRowNum, endRowNum))
}
*/
;=======================================================================================
; Method: LV_Drag()
; Description: Drag-and-Drop row showing a destination bar.
; Parameters:
; AutoScroll: If true or omitted the ListView will automatically scroll
; up or down when the cursor is above or below the control.
; ScrollDelay: Delay in miliseconds for AutoScroll. Default is 100ms.
; LineThick: Thickness of the destination bar in pixels. Default is 2px.
; Color: Color of destination bar. Default is "Black".
; Return: The destination row number.
;=======================================================================================
LV_Drag(AutoScroll := true, ScrollDelay := 100, LineThick := 2, Color := "Black")
{
Static LVIR_LABEL := 0x0002
Static LVM_GETITEMCOUNT := 0x1004
Static LVM_SCROLL := 0x1014
Static LVM_GETTOPINDEX := 0x1027
Static LVM_GETCOUNTPERPAGE := 0x1028
Static LVM_GETSUBITEMRECT := 0x1038
Static LV_currColHeight := 0
Static MarkLineGui := Gui()
SM_CXVSCROLL := SysGet(2)
old_CoordModeMouse := A_CoordModeMouse
CoordMode("Mouse", "Client")
MouseGetPos(, , &LV_Win, &LV_LView, 2)
WinGetClientPos(&Win_X, &Win_Y, &Win_W, &Win_H, "ahk_id " LV_Win)
ControlGetPos(&LV_lx, &LV_ly, &LV_lw, &LV_lh, LV_LView)
LV_lw := LV_lw * 96 // A_ScreenDPI
LV_XYstruct := Buffer(16, 0)
While (GetKeyState("LButton", "P"))
{
MouseGetPos(&LV_mx, &LV_my, , &CurrCtrl, 2)
If (AutoScroll)
{
LV_mx -= LV_lx, LV_my -= LV_ly
If (LV_my < 0)
{
SendMessage(LVM_SCROLL, 0, -LV_currColHeight, , LV_LView)
Sleep(ScrollDelay)
}
If (LV_my > LV_lh)
{
SendMessage(LVM_SCROLL, 0, LV_currColHeight, , LV_LView)
Sleep(ScrollDelay)
}
}
If (CurrCtrl != LV_LView)
{
LV_currRow := ""
MarkLineGui.Hide()
continue
}
LV_TotalNumOfRows := SendMessage(LVM_GETITEMCOUNT, 0, 0, , LV_LView)
LV_NumOfRows := SendMessage(LVM_GETCOUNTPERPAGE, 0, 0, , LV_LView)
LV_topIndex := SendMessage(LVM_GETTOPINDEX, 0, 0, , LV_LView)
Line_W := (LV_TotalNumOfRows > LV_NumOfRows) ? LV_lw - SM_CXVSCROLL : LV_lw
Loop LV_NumOfRows + 1
{
LV_which := LV_topIndex + A_Index - 1
NumPut("UInt", LVIR_LABEL, LV_XYstruct, 0)
NumPut("UInt", A_Index - 1, LV_XYstruct, 4)
SendMessage(LVM_GETSUBITEMRECT, LV_which, LV_XYstruct.Ptr, , LV_LView)
LV_RowY := NumGet(LV_XYstruct, 4, "UInt")
, LV_RowY2 := NumGet(LV_XYstruct, 12, "UInt")
, LV_currColHeight := LV_RowY2 - LV_RowY
If (LV_my <= LV_RowY + LV_currColHeight)
{
LV_currRow := LV_which + 1
, LV_currRow0 := LV_which
, Line_Y := Win_Y + LV_ly + LV_RowY
, Line_X := Win_X + LV_lx
If (LV_currRow > (LV_TotalNumOfRows + 1))
{
MarkLineGui.Hide()
LV_currRow := ""
}
Break
}
}
If (LV_currRow)
{
MarkLineGui.BackColor := Color
MarkLineGui.Opt("+LastFound +AlwaysOnTop +Toolwindow -Caption")
MarkLineGui.Show(Format("w{} h{} y{} x{} NoActivate", Line_W, LineThick, Line_Y, Line_X))
}
}
MarkLineGui.Hide()
CoordMode("Mouse", old_CoordModeMouse)
return LV_currRow
}