Jump to content
Sign in to follow this  
someone

Listview sort method

Recommended Posts

someone

Hey everyone,

I have a listview I am sorting when the user clicks on the header, and everything is working OK except I would love a way to know what column is sorted and how (ascending/descending).

I'm using _GUICtrlListView_RegisterSortCallBack/_GUICtrlListView_SortItems. I do have code but its pretty large and I'm not sure it would help to show. Maybe there is a way to know which column/way the arrow is drawn with _RegisterSortCallBack? Not sure if that would be a different method than knowing what column is sorted though.

Thanks for the help in advance.


While ProcessExists('Andrews bad day.exe')
	BlockInput(1)
	SoundPlay('Music.wav')
	SoundSetWaveVolume('Louder')
WEnd

Share this post


Link to post
Share on other sites
Melba23

someone,

I knew you could easily get the column value when using GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") and _GUICtrlListView_SimpleSort by using a Global variable:

$tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
$iColumn = DllStructGetData($tInfo, "SubItem")

But in trying to find a solution to your problem I have discovered that this method will not work when using _GUICtrlListView_RegisterSortCallBack and _GUICtrlListView_SortItems, even though the WM_NOTIFY function is essentially the same. The $iColumn = DllStructGetData($tInfo, "SubItem") code still works within the function (because using the value obtained as a _GUICtrlListView_SortItems parameter works perfectly), but I cannot find any way of getting the value out of the function. It does not update a global variable, nor will it ConsoleWrite - it is as if there was something preventing the WM_NOTIFY function from having anything to do with the rest of the script when used with _GUICtrlListView_RegisterSortCallBack!

I did try using both GUIRegisterMsg and _GUICtrlListView_RegisterSortCallBack in teh same script - I got the column index, but no sorting! :-(

I am now at the edge of my (limited) knowledge of this area of AutoIt - perhaps one of the gurus could shed some light on this for us both.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
picaxe

I have a listview I am sorting when the user clicks on the header, and everything is working OK except I would love a way to know what column is sorted and how (ascending/descending).

One way is to use a modified version of _GUICtrlListView_SortItems
#include <GuiConstantsEx.au3>
#include <GuiListView.au3>
#include <File.au3>
#include <WindowsConstants.au3>

Global $iColumn, $sSortDirection

$Gui = GUICreate("Test", 300, 200)
$hListView = GUICtrlCreateListView("Items|SubItems", 2, 2, 296, 196, BitOR($LVS_EDITLABELS, $LVS_REPORT))
_GUICtrlListView_SetExtendedListViewStyle($hListView, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT, $LVS_EX_DOUBLEBUFFER ))

$sItems ="Item9,44|Item2,22|Item1,11|Item2,33|Item3,|Item1,|Item2,|Item3,|Item1,"
$aFile = StringSplit($sItems, "|")

$iSize = $aFile[0]
Dim $result[$iSize][2]

For $x = 1 To $iSize
    $aCol = StringSplit($aFile[$x], ",")
    $iIndex = _GUICtrlListView_AddItem($hListView, $aCol[1], -1, $x);_GUICtrlListView_GetItemCount($hListView))
    For $y = 2 To $aCol[0]
        _GUICtrlListView_AddSubItem($hListView, $iIndex, $aCol[$y], $y - 1)
    Next
Next
GUISetState()

_GUICtrlListView_RegisterSortCallBack($hListView)
While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $hListView
            ; use modified sort callback
            __GUICtrlListView_SortItems($hListView, GUICtrlGetState($hListView))
            ConsoleWrite("Column: " & $iColumn & "  Sort: " & $sSortDirection & @LF)
    EndSwitch
WEnd
_GUICtrlListView_UnRegisterSortCallBack($hListView)
GUIDelete()

; modified sort call back from include GuiListView.au3
Func __GUICtrlListView_SortItems($hWnd, $iCol)
    Local $iResult, $iIndex, $pFunction, $hHeader, $iFormat

    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)

    For $x = 1 To $aListViewSortInfo[0][0]
        If $hWnd = $aListViewSortInfo[$x][1] Then
            $iIndex = $x
            ExitLoop
        EndIf
    Next

    $pFunction = DllCallbackGetPtr($aListViewSortInfo[$iIndex][2]) ; get pointer to call back
    $aListViewSortInfo[$iIndex][3] = $iCol ; $nColumn = column clicked
    $aListViewSortInfo[$iIndex][7] = 0 ; $bSet
    $aListViewSortInfo[$iIndex][4] = $aListViewSortInfo[$iIndex][6] ; nCurCol = $nCol
    $iResult = _SendMessage($hWnd, $LVM_SORTITEMS, $hWnd, $pFunction, 0, "hwnd", "ptr")
    If $iResult <> 0 Then
        If $aListViewSortInfo[$iIndex][9] Then ; Use arrow in header
            $hHeader = $aListViewSortInfo[$iIndex][10]
            For $x = 0 To _GUICtrlHeader_GetItemCount($hHeader) - 1
                $iFormat = _GUICtrlHeader_GetItemFormat($hHeader, $x)
                If BitAND($iFormat, $HDF_SORTDOWN) Then
                    _GUICtrlHeader_SetItemFormat($hHeader, $x, BitXOR($iFormat, $HDF_SORTDOWN))
                ElseIf BitAND($iFormat, $HDF_SORTUP) Then
                    _GUICtrlHeader_SetItemFormat($hHeader, $x, BitXOR($iFormat, $HDF_SORTUP))
                EndIf
            Next
            $iFormat = _GUICtrlHeader_GetItemFormat($hHeader, $iCol)
            If $aListViewSortInfo[$iIndex][5] = 1 Then ; ascending
                _GUICtrlHeader_SetItemFormat($hHeader, $iCol, BitOR($iFormat, $HDF_SORTUP))
                $iColumn = $iCol
                $sSortDirection = "Ascending"
            Else ; descending
                _GUICtrlHeader_SetItemFormat($hHeader, $iCol, BitOR($iFormat, $HDF_SORTDOWN))
                $iColumn = $iCol
                $sSortDirection = "Descending"
            EndIf
        EndIf
    EndIf

    Return $iResult <> 0
    
EndFunc   ;==>_GUICtrlListView_SortItems

Share this post


Link to post
Share on other sites
Melba23

someone,

I have a solution. You need to read the $aListViewSortInfo array created by the GuiListView.au3 include file within your While...WEnd loop after calling _GUICtrlListView_SortItems. So the loop in the _GUICtrlListView_SortItems example would look like this:

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $hListView
; Kick off the sort callback
            _GUICtrlListView_SortItems($hListView, GUICtrlGetState($hListView))
            Local $iIndex = $aListViewSortInfo[0][0]
            ConsoleWrite("Col: " & $aListViewSortInfo[$iIndex][3])
            If $aListViewSortInfo[$iIndex][5] = 1 Then
                ConsoleWrite(" in ascending order" & @CRLF)
            Else
                ConsoleWrite(" in descending order" & @CRLF)
            EndIf
    EndSwitch
WEnd

I hope this works for you.

M23

Edit: picaxe, Looks like you beat me to it by a very short head. I must learn to type faster!

Edited by Melba23

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
someone

Thank you both very much, really appreciate it. Looks likes its exactly what I was hoping for. Any chance either of you know how to highlight in a listview? I want to have permanent highlighting (not done by a user) based on the information populated, say if colum a says 'here' I want the row to be highlighted red, if it says 'there' I want it highlighted yellow, etc.

I haven't done as much searching around for that but any pointers is of course greatly appreciated.

Not a huge deal but it would be pretty cool to do.

Thanks again!


While ProcessExists('Andrews bad day.exe')
	BlockInput(1)
	SoundPlay('Music.wav')
	SoundSetWaveVolume('Louder')
WEnd

Share this post


Link to post
Share on other sites
picaxe

Thank you both very much, really appreciate it. Looks likes its exactly what I was hoping for. Any chance either of you know how to highlight in a listview? I want to have permanent highlighting (not done by a user) based on the information populated, say if colum a says 'here' I want the row to be highlighted red, if it says 'there' I want it highlighted yellow, etc.

The examples forum has many custom drawn examples from Siao and others that can do that. My version of a simple example
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <WindowsConstants.au3>
#include <HeaderConstants.au3>
#Include <SendMessage.au3>
#include <ListViewConstants.au3>
#Include <WinAPI.au3>

$GUI = GUICreate("Test Script", 300, 230)

$ListView = GUICtrlCreateListView("Column", 20, 10, 260, 160, $LVS_REPORT)
$hListView = GUICtrlGetHandle($ListView)
_GUICtrlListView_SetColumnWidth($hListView, 0, 250)
For $i = 0 To 20
    GUICtrlCreateListViewItem("Test Item " & StringFormat("%.03u", $i), $ListView)
Next
;~ $Highlight_Button = GUICtrlCreateButton("Highlight", 20, 190, 80, 20)
;~ $Clear_Button = GUICtrlCreateButton("Clear", 200, 190, 80, 20)

GUISetState(@SW_SHOW, $GUI)
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

;fonts for custom draw example
;bold
Local $aFontBold = DLLCall("gdi32.dll","int","CreateFont", "int", 14, "int", 0, "int", 0, "int", 0, "int", 700, _
                        "dword", 0, "dword", 0, "dword", 0, "dword", 0, "dword", 0, "dword", 0, "dword", 0, _
                        "dword", 0, "str", "")
;italic
Local $aFontItalic = DLLCall("gdi32.dll","int","CreateFont", "int", 14, "int", 0, "int", 0, "int", 0, "int", 400, _
                        "dword", 1, "dword", 0, "dword", 0, "dword", 0, "dword", 0, "dword", 0, "dword", 0, _
                        "dword", 0, "str", "")
                        
                        
; hilite the following rows
$iIndex = "|2|5|7|11|18|"
_WinAPI_RedrawWindow($hListView)


;$iIndex = -1
While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            DLLCall("gdi32.dll","int","DeleteObject", "hwnd", $aFontBold[0])
            DLLCall("gdi32.dll","int","DeleteObject", "hwnd", $aFontItalic[0])
            Exit
;~       Case $Highlight_Button
;~           $iIndex = _GUICtrlListView_GetSelectedIndices($hListView)
;~          _WinAPI_RedrawWindow($hListView)
;~       Case $Clear_Button
;~          $iIndex = -1
;~          _WinAPI_RedrawWindow($hListView)
    EndSwitch
WEnd

Func WM_NOTIFY($hWnd, $Msg, $wParam, $lParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hListView
            Switch $iCode
                Case $NM_CUSTOMDRAW
                    If Not _GUICtrlListView_GetViewDetails($hWndFrom) Then Return $GUI_RUNDEFMSG
                    Local $tCustDraw = DllStructCreate('hwnd hwndFrom;int idFrom;int code;' & _
                            'dword DrawStage;hwnd hdc;long rect[4];dword ItemSpec;int ItemState;dword Itemlparam;' & _
                            'dword clrText;dword clrTextBk;int SubItem;dword ItemType;dword clrFace;int IconEffect;' & _
                            'int IconPhase;int PartID;int StateID;long rectText[4];int Align', _;winxp or later
                            $lParam)
                    Local $iDrawStage, $iItem, $iSubitem, $hDC, $iColor1, $iColor2, $iColor3
                    $iDrawStage = DllStructGetData($tCustDraw, 'DrawStage')
                    If $iDrawStage = $CDDS_PREPAINT Then Return $CDRF_NOTIFYITEMDRAW;request custom drawing of items
                    If $iDrawStage = $CDDS_ITEMPREPAINT Then Return $CDRF_NOTIFYSUBITEMDRAW;request drawing each cell separately
                    If Not BitAND($iDrawStage, $CDDS_SUBITEM) Then Return $CDRF_DODEFAULT
                    $iItem = DllStructGetData($tCustDraw, 'ItemSpec')
                ;$iSubitem = DllStructGetData($tCustDraw, 'SubItem')
                ;$iColor1 = RGB2BGR(0xFBFFD8); light yellow
                    $iColor1 = RGB2BGR(0xFFFFA8); yellow
                ;$iColor1 = RGB2BGR(0xFFDDDD); light red
                    $iColor2 = RGB2BGR(-1)      ; white
                ;$iColor3 = RGB2BGR(0xFF0000); red
                    $iColor3 = RGB2BGR(0xFF6060); light red
                ;$iColor3 = RGB2BGR(0x000080); navy blue
                    If $iIndex = -1 Then Return $CDRF_NEWFONT
                    If StringInStr($iIndex, "|" & $iItem & "|") Then
                        $hDC = DllStructGetData($tCustDraw, 'hdc')
                        DLLCall("gdi32.dll","hwnd","SelectObject", "hwnd", $hDC, "hwnd", $aFontBold[0])
                        DllStructSetData($tCustDraw, 'clrText', $iColor2)
                        DllStructSetData($tCustDraw, 'clrTextBk', $iColor3)
                    EndIf
                    Return $CDRF_NEWFONT
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc  ;==>WM_NOTIFY

Func RGB2BGR($iColor)
    Return BitAND(BitShift(String(Binary($iColor)), 8), 0xFFFFFF)
EndFunc  ;==>RGB2BGR

Share this post


Link to post
Share on other sites
Melba23

picaxe,

Thanks for that script. I was having trouble understanding some of the other examples I came across - I find yours much easier for some reason. Always delighted to learn something new. :-)

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
someone

Yeah very cool, thanks a lot guys


While ProcessExists('Andrews bad day.exe')
	BlockInput(1)
	SoundPlay('Music.wav')
	SoundSetWaveVolume('Louder')
WEnd

Share this post


Link to post
Share on other sites

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  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.