like the pic below I make a Autohotkey Gui, I want to make Rubberband selection to select multiple items as the 2nd pic. Can any one help me?
How to make Rubberband selection to select multiple items in Autohotkey v2 listview?
-
- Posts: 4412
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: How to make Rubberband selection to select multiple items in Autohotkey v2 listview?
Try:
Code: Select all
#Requires AutoHotkey v2
wnd := Gui()
wnd.OnEvent('Close', (*) => ExitApp())
wnd.SetFont('s12', 'Calibri')
lv := wnd.Add('ListView', 'r10 w400', ['Name','Size (KB)'])
Loop Files, A_MyDocuments . '\*.*' {
lv.Add(, A_LoopFileName, A_LoopFileSizeKB)
}
lv.ModifyCol(1, 'AutoHdr')
lv.ModifyCol(2, 'AutoHdr Integer')
wnd.Show()
OnMessage(0x201, WM_LBUTTONDOWN)
WM_LBUTTONDOWN(wp, lp, msg, hwnd) {
static LVM_HITTEST := 0x1012, LVM_ISITEMVISIBLE := 0x10B6, LVM_GETITEMRECT := 0x100E
res := true
if hwnd == lv.hwnd {
NumPut('Int', lp & 0xFFFF, 'Int', lp >> 16, buf := Buffer(24))
res := SendMessage(LVM_HITTEST,, buf, lv) != -1
}
if res {
WinGetPos(&x, &y,,, lv)
lv.itemRects := []
Loop lv.GetCount() {
i := A_Index - 1
if !SendMessage(LVM_ISITEMVISIBLE, i,, lv) {
lv.itemRects.Push('')
continue
}
SendMessage LVM_GETITEMRECT, i, RECT := Buffer(16, 0), lv
NumPut('Int', x,
'Int', NumGet(RECT, 4, 'Int') + y,
'Int', NumGet(RECT, 8, 'Int') + x,
'Int', NumGet(RECT, 12, 'Int') + y, RECT)
lv.itemRects.Push(RECT)
}
lv.area := SelectArea(0x5A00AAEE, SelectItems)
}
}
SelectItems(p1, p2) {
static testRECT := Buffer(16)
NumPut('Int', p1['x'], 'Int', p1['y'], 'Int', p2['x'], 'Int', p2['y'], RECT := Buffer(16))
for i, itemRECT in lv.itemRects {
res := itemRECT && DllCall('IntersectRect', 'Ptr', testRECT, 'Ptr', RECT, 'Ptr', itemRECT)
lv.Modify(i, (res ? '' : '-') . 'Select')
}
}
~*LButton Up:: lv.area := ''
class SelectArea
{
WH_MOUSE_LL := 14, WM_MOUSEMOVE := 0x200
__New(colorARGB, callback?) {
IsSet(callback) && this.callback := callback
this.CreateGui(colorARGB)
CoordMode 'Mouse'
MouseGetPos &x, &y
this.startX := x
this.startY := y
this.hook := WindowsHook(this.WH_MOUSE_LL, LowLevelMouseProc)
ObjRelease(ObjPtr(this))
LowLevelMouseProc(nCode, wParam, lParam) {
if wParam == this.WM_MOUSEMOVE {
mouseX := NumGet(lParam + 0, 'Int')
mouseY := NumGet(lParam + 4, 'Int')
this.ShowBetweenTwoPoints(Map('x', this.startX, 'y', this.startY), Map('x', mouseX, 'y', mouseY))
}
return DllCall('CallNextHookEx', 'Ptr', 0, 'Int', nCode, 'UInt', wParam, 'Ptr', lParam, 'Ptr')
}
}
__Delete() {
ObjAddRef(ObjPtr(this))
this.hook := ''
this.gui.Destroy()
}
CreateGui(colorARGB) {
wnd := Gui('-Caption ToolWindow AlwaysOnTop Border -DPIScale')
wnd.BackColor := Format('{:X}', colorARGB & 0xFFFFFF)
WinSetTransparent(colorARGB >> 24, wnd)
this.gui := wnd
}
ShowBetweenTwoPoints(p1, p2) {
p1['x'] < p2['x'] ? (x1 := p1['x'], x2 := p2['x']) : (x1 := p2['x'], x2 := p1['x'])
p1['y'] < p2['y'] ? (y1 := p1['y'], y2 := p2['y']) : (y1 := p2['y'], y2 := p1['y'])
this.gui.Show('NA x' . x1 . ' y' . y1 . ' w' . x2 - x1 . ' h' . y2 - y1)
Loop 2 {
this.x%A_Index% := x%A_Index%
this.y%A_Index% := y%A_Index%
}
if this.HasOwnProp('callback') {
this.callback.Call(Map('x', this.x1, 'y', this.y1), Map('x', this.x2, 'y', this.y2))
}
}
}
class WindowsHook {
__New(type, callback, isGlobal := true) {
this.pCallback := CallbackCreate(callback, 'Fast', 3)
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)
CallbackFree(this.pCallback)
}
}
Re: How to make Rubberband selection to select multiple items in Autohotkey v2 listview?
Awesome... Thank you!
Re: How to make Rubberband selection to select multiple items in Autohotkey v2 listview?
Thanks! but when Rubberband selecting, it will deselect the previous selected items. Is it possible not to do that when "Ctrl" is pressed? (Like File Explorer, when "Ctrl" is pressed, Rubberband selecting won't deselect the already selected items.teadrinker wrote: ↑24 May 2024, 14:20Try:Code: Select all
#Requires AutoHotkey v2 wnd := Gui() wnd.OnEvent('Close', (*) => ExitApp()) wnd.SetFont('s12', 'Calibri') lv := wnd.Add('ListView', 'r10 w400', ['Name','Size (KB)']) Loop Files, A_MyDocuments . '\*.*' { lv.Add(, A_LoopFileName, A_LoopFileSizeKB) } lv.ModifyCol(1, 'AutoHdr') lv.ModifyCol(2, 'AutoHdr Integer') wnd.Show() OnMessage(0x201, WM_LBUTTONDOWN) WM_LBUTTONDOWN(wp, lp, msg, hwnd) { static LVM_HITTEST := 0x1012, LVM_ISITEMVISIBLE := 0x10B6, LVM_GETITEMRECT := 0x100E res := true if hwnd == lv.hwnd { NumPut('Int', lp & 0xFFFF, 'Int', lp >> 16, buf := Buffer(24)) res := SendMessage(LVM_HITTEST,, buf, lv) != -1 } if res { WinGetPos(&x, &y,,, lv) lv.itemRects := [] Loop lv.GetCount() { i := A_Index - 1 if !SendMessage(LVM_ISITEMVISIBLE, i,, lv) { lv.itemRects.Push('') continue } SendMessage LVM_GETITEMRECT, i, RECT := Buffer(16, 0), lv NumPut('Int', x, 'Int', NumGet(RECT, 4, 'Int') + y, 'Int', NumGet(RECT, 8, 'Int') + x, 'Int', NumGet(RECT, 12, 'Int') + y, RECT) lv.itemRects.Push(RECT) } lv.area := SelectArea(0x5A00AAEE, SelectItems) } } SelectItems(p1, p2) { static testRECT := Buffer(16) NumPut('Int', p1['x'], 'Int', p1['y'], 'Int', p2['x'], 'Int', p2['y'], RECT := Buffer(16)) for i, itemRECT in lv.itemRects { res := itemRECT && DllCall('IntersectRect', 'Ptr', testRECT, 'Ptr', RECT, 'Ptr', itemRECT) lv.Modify(i, (res ? '' : '-') . 'Select') } } ~*LButton Up:: lv.area := '' class SelectArea { WH_MOUSE_LL := 14, WM_MOUSEMOVE := 0x200 __New(colorARGB, callback?) { IsSet(callback) && this.callback := callback this.CreateGui(colorARGB) CoordMode 'Mouse' MouseGetPos &x, &y this.startX := x this.startY := y this.hook := WindowsHook(this.WH_MOUSE_LL, LowLevelMouseProc) ObjRelease(ObjPtr(this)) LowLevelMouseProc(nCode, wParam, lParam) { if wParam == this.WM_MOUSEMOVE { mouseX := NumGet(lParam + 0, 'Int') mouseY := NumGet(lParam + 4, 'Int') this.ShowBetweenTwoPoints(Map('x', this.startX, 'y', this.startY), Map('x', mouseX, 'y', mouseY)) } return DllCall('CallNextHookEx', 'Ptr', 0, 'Int', nCode, 'UInt', wParam, 'Ptr', lParam, 'Ptr') } } __Delete() { ObjAddRef(ObjPtr(this)) this.hook := '' this.gui.Destroy() } CreateGui(colorARGB) { wnd := Gui('-Caption ToolWindow AlwaysOnTop Border -DPIScale') wnd.BackColor := Format('{:X}', colorARGB & 0xFFFFFF) WinSetTransparent(colorARGB >> 24, wnd) this.gui := wnd } ShowBetweenTwoPoints(p1, p2) { p1['x'] < p2['x'] ? (x1 := p1['x'], x2 := p2['x']) : (x1 := p2['x'], x2 := p1['x']) p1['y'] < p2['y'] ? (y1 := p1['y'], y2 := p2['y']) : (y1 := p2['y'], y2 := p1['y']) this.gui.Show('NA x' . x1 . ' y' . y1 . ' w' . x2 - x1 . ' h' . y2 - y1) Loop 2 { this.x%A_Index% := x%A_Index% this.y%A_Index% := y%A_Index% } if this.HasOwnProp('callback') { this.callback.Call(Map('x', this.x1, 'y', this.y1), Map('x', this.x2, 'y', this.y2)) } } } class WindowsHook { __New(type, callback, isGlobal := true) { this.pCallback := CallbackCreate(callback, 'Fast', 3) 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) CallbackFree(this.pCallback) } }
-
- Posts: 4412
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: How to make Rubberband selection to select multiple items in Autohotkey v2 listview?
In this variant, Rubberband behaves the same way as in Windows Explorer: if the selection rectangle crosses a previously selected line, the selection is deselected; if the line was not selected, it is selected.
Code: Select all
#Requires AutoHotkey v2
wnd := Gui()
wnd.OnEvent('Close', (*) => ExitApp())
wnd.SetFont('s12', 'Calibri')
lv := wnd.Add('ListView', 'r10 w400', ['Name','Size (KB)'])
Loop Files, A_MyDocuments . '\*.*' {
lv.Add(, A_LoopFileName, A_LoopFileSizeKB)
}
lv.ModifyCol(1, 'AutoHdr')
lv.ModifyCol(2, 'AutoHdr Integer')
wnd.Show()
OnMessage(0x201, WM_LBUTTONDOWN)
WM_LBUTTONDOWN(wp, lp, msg, hwnd) {
static LVM_HITTEST := 0x1012, LVM_ISITEMVISIBLE := 0x10B6, LVM_GETITEMRECT := 0x100E
res := true
lv.prevSelected := Map()
if GetKeyState('Ctrl', 'P') {
i := 0
while i := lv.GetNext(i) {
lv.prevSelected[i] := ''
}
}
if hwnd == lv.hwnd {
NumPut('Int', lp & 0xFFFF, 'Int', lp >> 16, buf := Buffer(24))
res := SendMessage(LVM_HITTEST,, buf, lv) != -1
}
if res {
WinGetPos(&x, &y,,, lv)
lv.itemRects := []
Loop lv.GetCount() {
i := A_Index - 1
if !SendMessage(LVM_ISITEMVISIBLE, i,, lv) {
lv.itemRects.Push('')
continue
}
SendMessage LVM_GETITEMRECT, i, RECT := Buffer(16, 0), lv
NumPut('Int', x,
'Int', NumGet(RECT, 4, 'Int') + y,
'Int', NumGet(RECT, 8, 'Int') + x,
'Int', NumGet(RECT, 12, 'Int') + y, RECT)
lv.itemRects.Push(RECT)
}
lv.area := SelectArea(0x5A00AAEE, SelectItems)
}
}
SelectItems(p1, p2) {
static testRECT := Buffer(16)
NumPut('Int', p1['x'], 'Int', p1['y'], 'Int', p2['x'], 'Int', p2['y'], RECT := Buffer(16))
for i, itemRECT in lv.itemRects {
res := itemRECT && DllCall('IntersectRect', 'Ptr', testRECT, 'Ptr', RECT, 'Ptr', itemRECT)
lv.Modify(i, (res ^ lv.prevSelected.Has(i) ? '' : '-') . 'Select')
}
}
~*LButton Up:: lv.area := ''
class SelectArea
{
WH_MOUSE_LL := 14, WM_MOUSEMOVE := 0x200
__New(colorARGB, callback?) {
IsSet(callback) && this.callback := callback
this.CreateGui(colorARGB)
CoordMode 'Mouse'
MouseGetPos &x, &y
this.startX := x
this.startY := y
this.hook := WindowsHook(this.WH_MOUSE_LL, LowLevelMouseProc)
ObjRelease(ObjPtr(this))
LowLevelMouseProc(nCode, wParam, lParam) {
if wParam == this.WM_MOUSEMOVE {
mouseX := NumGet(lParam + 0, 'Int')
mouseY := NumGet(lParam + 4, 'Int')
this.ShowBetweenTwoPoints(Map('x', this.startX, 'y', this.startY), Map('x', mouseX, 'y', mouseY))
}
return DllCall('CallNextHookEx', 'Ptr', 0, 'Int', nCode, 'UInt', wParam, 'Ptr', lParam, 'Ptr')
}
}
__Delete() {
ObjAddRef(ObjPtr(this))
this.hook := ''
this.gui.Destroy()
}
CreateGui(colorARGB) {
wnd := Gui('-Caption ToolWindow AlwaysOnTop Border -DPIScale')
wnd.BackColor := Format('{:X}', colorARGB & 0xFFFFFF)
WinSetTransparent(colorARGB >> 24, wnd)
this.gui := wnd
}
ShowBetweenTwoPoints(p1, p2) {
p1['x'] < p2['x'] ? (x1 := p1['x'], x2 := p2['x']) : (x1 := p2['x'], x2 := p1['x'])
p1['y'] < p2['y'] ? (y1 := p1['y'], y2 := p2['y']) : (y1 := p2['y'], y2 := p1['y'])
this.gui.Show('NA x' . x1 . ' y' . y1 . ' w' . x2 - x1 . ' h' . y2 - y1)
Loop 2 {
this.x%A_Index% := x%A_Index%
this.y%A_Index% := y%A_Index%
}
if this.HasOwnProp('callback') {
this.callback.Call(Map('x', this.x1, 'y', this.y1), Map('x', this.x2, 'y', this.y2))
}
}
}
class WindowsHook {
__New(type, callback, isGlobal := true) {
this.pCallback := CallbackCreate(callback, 'Fast', 3)
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)
CallbackFree(this.pCallback)
}
}
Re: How to make Rubberband selection to select multiple items in Autohotkey v2 listview?
Fyi... the code seems to have a bug. As soon as I tried to click-drag, it locked my computer up so I am unable to provide any more details. But I did see, "expected a number but got an empty string" prior to forced POPO. The errors came so rapidly that it is probably related to mouse coords. I don't dare run it again. lol.
-
- Posts: 4412
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: How to make Rubberband selection to select multiple items in Autohotkey v2 listview?
@andymbody
Understood what might have been the issue, fixed, please try again:
Understood what might have been the issue, fixed, please try again:
Code: Select all
#Requires AutoHotkey v2
wnd := Gui()
wnd.OnEvent('Close', (*) => ExitApp())
wnd.SetFont('s12', 'Calibri')
lv := wnd.Add('ListView', 'r10 w400', ['Name','Size (KB)'])
Loop Files, A_MyDocuments . '\*.*' {
lv.Add(, A_LoopFileName, A_LoopFileSizeKB)
}
lv.ModifyCol(1, 'AutoHdr')
lv.ModifyCol(2, 'AutoHdr Integer')
wnd.Show()
OnMessage(0x201, WM_LBUTTONDOWN)
WM_LBUTTONDOWN(wp, lp, msg, hwnd) {
static LVM_HITTEST := 0x1012, LVM_ISITEMVISIBLE := 0x10B6, LVM_GETITEMRECT := 0x100E
res := true
lv.prevSelected := Map()
if GetKeyState('Ctrl', 'P') {
i := 0
while i := lv.GetNext(i) {
lv.prevSelected[i] := ''
}
}
if hwnd == lv.hwnd {
NumPut('Int', lp & 0xFFFF, 'Int', lp >> 16, buf := Buffer(24))
res := SendMessage(LVM_HITTEST,, buf, lv) != -1
}
if res {
WinGetPos(&x, &y,,, lv)
lv.itemRects := []
Loop lv.GetCount() {
i := A_Index - 1
if !SendMessage(LVM_ISITEMVISIBLE, i,, lv) {
lv.itemRects.Push('')
continue
}
SendMessage LVM_GETITEMRECT, i, RECT := Buffer(16, 0), lv
NumPut('Int', x,
'Int', NumGet(RECT, 4, 'Int') + y,
'Int', NumGet(RECT, 8, 'Int') + x,
'Int', NumGet(RECT, 12, 'Int') + y, RECT)
lv.itemRects.Push(RECT)
}
lv.area := SelectArea(0x5A00AAEE, SelectItems)
}
}
SelectItems(p1, p2) {
static testRECT := Buffer(16)
NumPut('Int', p1['x'], 'Int', p1['y'], 'Int', p2['x'], 'Int', p2['y'], RECT := Buffer(16))
for i, itemRECT in lv.itemRects {
res := itemRECT && DllCall('IntersectRect', 'Ptr', testRECT, 'Ptr', RECT, 'Ptr', itemRECT)
lv.Modify(i, (!!res ^ lv.prevSelected.Has(i) ? '' : '-') . 'Select')
}
}
~*LButton Up:: lv.area := ''
class SelectArea
{
WH_MOUSE_LL := 14, WM_MOUSEMOVE := 0x200
__New(colorARGB, callback?) {
IsSet(callback) && this.callback := callback
this.CreateGui(colorARGB)
CoordMode 'Mouse'
MouseGetPos &x, &y
this.startX := x
this.startY := y
this.hook := WindowsHook(this.WH_MOUSE_LL, LowLevelMouseProc)
ObjRelease(ObjPtr(this))
LowLevelMouseProc(nCode, wParam, lParam) {
if wParam == this.WM_MOUSEMOVE {
mouseX := NumGet(lParam + 0, 'Int')
mouseY := NumGet(lParam + 4, 'Int')
this.ShowBetweenTwoPoints(Map('x', this.startX, 'y', this.startY), Map('x', mouseX, 'y', mouseY))
}
return DllCall('CallNextHookEx', 'Ptr', 0, 'Int', nCode, 'UInt', wParam, 'Ptr', lParam, 'Ptr')
}
}
__Delete() {
ObjAddRef(ObjPtr(this))
this.hook := ''
this.gui.Destroy()
}
CreateGui(colorARGB) {
wnd := Gui('-Caption ToolWindow AlwaysOnTop Border -DPIScale')
wnd.BackColor := Format('{:X}', colorARGB & 0xFFFFFF)
WinSetTransparent(colorARGB >> 24, wnd)
this.gui := wnd
}
ShowBetweenTwoPoints(p1, p2) {
p1['x'] < p2['x'] ? (x1 := p1['x'], x2 := p2['x']) : (x1 := p2['x'], x2 := p1['x'])
p1['y'] < p2['y'] ? (y1 := p1['y'], y2 := p2['y']) : (y1 := p2['y'], y2 := p1['y'])
this.gui.Show('NA x' . x1 . ' y' . y1 . ' w' . x2 - x1 . ' h' . y2 - y1)
Loop 2 {
this.x%A_Index% := x%A_Index%
this.y%A_Index% := y%A_Index%
}
if this.HasOwnProp('callback') {
this.callback.Call(Map('x', this.x1, 'y', this.y1), Map('x', this.x2, 'y', this.y2))
}
}
}
class WindowsHook {
__New(type, callback, isGlobal := true) {
this.pCallback := CallbackCreate(callback, 'Fast', 3)
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)
CallbackFree(this.pCallback)
}
}
Re: How to make Rubberband selection to select multiple items in Autohotkey v2 listview?
Yep... works... thanks! Need to study your code to see how this was done. I may look into how to get it to scroll when selecting as well. But have other priorities at the moment.
Thank you very much! This is great!
Andy
-
- Posts: 4412
- Joined: 29 Mar 2015, 09:41
- Contact:
Who is online
Users browsing this forum: Draken, Jacquesyip, just me, marypoppins_1, Shekhar Singh and 27 guests