Update 2012-01-05 changes:
- Fixed column data not being retained properly. Thanks gwarble.
Update 2011-05-13 changes:
- Reduced function code by 3 lines.
- Very slightly improved performance.
Update 2011-03-24 changes:
- Added set direction support.
- Added return value of LVM_SETCOLUMN.
- Cleaned up code.
Update 2011-03-16 changes:
- Now supports AutoHotkey Basic, AutoHotkey_L (32-bit, 64-bit, ANSI/Unicode).
- Fixed 64-bit support and fmt style application. (thanks HotKeyIt)
AHK Support:
AutoHotkey Basic.
AutoHotkey_L All builds.
Usage:
You only need to include the function and insert 2 lines of code into your ListView's g-label:
If (A_GuiEvent = "ColClick") LV_SortArrow(hListView, A_EventInfo)See full example below.
Function (download):
; LV_SortArrow by Solar. http://www.autohotkey.com/forum/viewtopic.php?t=69642 ; h = ListView handle ; c = 1 based index of the column ; d = Optional direction to set the arrow. "asc" or "up". "desc" or "down". LV_SortArrow(h, c, d="") { static ptr, ptrSize, lvColumn, LVM_GETCOLUMN, LVM_SETCOLUMN if (!ptr) ptr := A_PtrSize ? ("ptr", ptrSize := A_PtrSize) : ("uint", ptrSize := 4) ,LVM_GETCOLUMN := A_IsUnicode ? (4191, LVM_SETCOLUMN := 4192) : (4121, LVM_SETCOLUMN := 4122) ,VarSetCapacity(lvColumn, ptrSize + 4), NumPut(1, lvColumn, "uint") c -= 1, DllCall("SendMessage", ptr, h, "uint", LVM_GETCOLUMN, "uint", c, ptr, &lvColumn) if ((fmt := NumGet(lvColumn, 4, "int")) & 1024) { if (d && d = "asc" || d = "up") return NumPut(fmt & ~1024 | 512, lvColumn, 4, "int") } else if (fmt & 512) { if (d && d = "desc" || d = "down") return NumPut(fmt & ~512 | 1024, lvColumn, 4, "int") } else { Loop % DllCall("SendMessage", ptr, DllCall("SendMessage", ptr, h, "uint", 4127), "uint", 4608) if ((i := A_Index - 1) != c) DllCall("SendMessage", ptr, h, "uint", LVM_GETCOLUMN, "uint", i, ptr, &lvColumn) ,NumPut(NumGet(lvColumn, 4, "int") & ~1536, lvColumn, 4, "int") ,DllCall("SendMessage", ptr, h, "uint", LVM_SETCOLUMN, "uint", i, ptr, &lvColumn) NumPut(fmt | (d && d = "desc" || d = "down" ? 512 : 1024), lvColumn, 4, "int") } return DllCall("SendMessage", ptr, h, "uint", LVM_SETCOLUMN, "uint", c, ptr, &lvColumn) }Example (download):
Gui, Add, ListView, r10 hwndhListView gListViewLabel, Sort Me|Sort Me 2 LV_ModifyCol(2, "Integer Left") Loop 10 LV_Add("", SubStr("abcdefghij", A_Index, 1), A_Index) Gui, Add, Button, Section gButton1, Col1 up/asc Gui, Add, Button, gButton2, Col1 down/desc Gui, Add, Button, ys gButton3, Col2 up/asc Gui, Add, Button, gButton4, Col2 down/desc Gui, Show,, ListView Sort Arrows Return ; this label will launch when a user interacts with our ListView. ListViewLabel: If (A_GuiEvent = "ColClick") ; A_GuiEvent tells us what kind of event triggered the label. LV_SortArrow(hListView, A_EventInfo) ; call the function if our column was clicked. Return Button1: LV_ModifyCol(1, "Sort"), LV_SortArrow(hListView, 1, "up") return Button2: LV_ModifyCol(1, "SortDesc"), LV_SortArrow(hListView, 1, "down") return Button3: LV_ModifyCol(2, "Sort"), LV_SortArrow(hListView, 2, "up") return Button4: LV_ModifyCol(2, "SortDesc"), LV_SortArrow(hListView, 2, "down") return GuiEscape: GuiClose: ExitApp ; LV_SortArrow by Solar. http://www.autohotkey.com/forum/viewtopic.php?t=69642 ; h = ListView handle ; c = 1 based index of the column ; d = Optional direction to set the arrow. "asc" or "up". "desc" or "down". LV_SortArrow(h, c, d="") { static ptr, ptrSize, lvColumn, LVM_GETCOLUMN, LVM_SETCOLUMN if (!ptr) ptr := A_PtrSize ? ("ptr", ptrSize := A_PtrSize) : ("uint", ptrSize := 4) ,LVM_GETCOLUMN := A_IsUnicode ? (4191, LVM_SETCOLUMN := 4192) : (4121, LVM_SETCOLUMN := 4122) ,VarSetCapacity(lvColumn, ptrSize + 4), NumPut(1, lvColumn, "uint") c -= 1, DllCall("SendMessage", ptr, h, "uint", LVM_GETCOLUMN, "uint", c, ptr, &lvColumn) if ((fmt := NumGet(lvColumn, 4, "int")) & 1024) { if (d && d = "asc" || d = "up") return NumPut(fmt & ~1024 | 512, lvColumn, 4, "int") } else if (fmt & 512) { if (d && d = "desc" || d = "down") return NumPut(fmt & ~512 | 1024, lvColumn, 4, "int") } else { Loop % DllCall("SendMessage", ptr, DllCall("SendMessage", ptr, h, "uint", 4127), "uint", 4608) if ((i := A_Index - 1) != c) DllCall("SendMessage", ptr, h, "uint", LVM_GETCOLUMN, "uint", i, ptr, &lvColumn) ,NumPut(NumGet(lvColumn, 4, "int") & ~1536, lvColumn, 4, "int") ,DllCall("SendMessage", ptr, h, "uint", LVM_SETCOLUMN, "uint", i, ptr, &lvColumn) NumPut(fmt | (d && d = "desc" || d = "down" ? 512 : 1024), lvColumn, 4, "int") } return DllCall("SendMessage", ptr, h, "uint", LVM_SETCOLUMN, "uint", c, ptr, &lvColumn) }Would appreciate any comments or questions. If you need help, feel free to ask.