Jump to content

ListView trap lparam for sort function


Recommended Posts

Hello forum,

I'm using a sort function to order dates and check boxes that requieres the following input parameters:

Func LVSort($hWnd, $nItem1, $nItem2, $nColumn)

Though I´m able to change the sort function according to the columns content,

I don´t know how to get the appropiate parameters for my sorting function from:

WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)

......

Case $LVN_COLUMNCLICK ;ListView column clicked

Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)

Local $iCol = DllStructGetData($tInfo, "SubItem") ;Column clicked starting from 0

Local $tNMLVCUSTOMDRAW = DllStructCreate($tagNMLVCUSTOMDRAW, $ilParam)

Local $dwItemSpec = DllStructGetData($tNMLVCUSTOMDRAW, "dwItemSpec") ; Item index

Local $iSubItem = DllStructGetData($tNMLVCUSTOMDRAW, "iSubItem") ; Subitem index

LVSort($idLV, $dwItemSpec, $dwItemSpec, $iCol)

I would appreciate if someone could help me.

thanks in advance and regards.

Edited by jcpetu
Link to comment
Share on other sites

An easier way to do it is to trigger off of the ListView to do it without the Windows messaging system. If you're using message loop mode, you would include a case statement for the listview's ID and do it like I have below.

#include <GUIConstantsEx.au3>
#include <GUIListView.au3>
$gui = GUICreate("Listview sorter")
$idListView = GUICtrlCreateListView("Column 1|Column 2", 10, 10, 300, 300)
$hListView = GUICtrlGetHandle($idListView)
For $I = 1 To 10
     GUICtrlCreateListViewItem($I * Random(1, 100, 1) & "|" & $I * Random(1, 100, 1), $idListView)
Next
GUISetState()
_GUICtrlListView_RegisterSortCallBack($hListView)
While 1
     $msg = GUIGetMsg()
     Switch $msg
          Case $GUI_Event_CLose
               _GUICtrlListView_UnRegisterSortCallBack($hListView)
               Exit
          Case $idListView
               sortLV()
     EndSwitch
WEnd
Func sortLV()
     Local $iCol = GUICtrlGetState($idListView)
     _GUICtrlListView_BeginUpdate($hListView)
     _GUICtrlListView_SortItems($hListView, $iCol)
     _GUICtrlListView_EndUpdate($hListView)
EndFunc   ;==>sortLV

It's a bit easier to do it this way than doing it with the Windows messages. It can also be done the same way if you use OnEvent mode.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

BrewManNH, thanks for your answer. I´m using a function that allows me to check the column and change the sorting algorithm, for example to sort dates and check boxes columns. In this example, how can I use a diferrente algorithm for dates?
Link to comment
Share on other sites

Hi jcpetu,

I understand your problems with sorting of the ListView. If you are using a native ListView you can register your own sorting callback function with GUICtrlRegisterListViewSort(). But if you are creating ListView's with the functions in GuiListView.au3 it's apparently not possible to use your own callback function with _GUICtrlListView_RegisterSortCallBack().

So you have to modify the sorting functions in GuiListView.au3 a little bit.

I have already modified the functions in the zip below. The following is just explanations.

Start to create a copy of the functions

_GUICtrlListView_RegisterSortCallBack()

__GUICtrlListView_Sort()

_GUICtrlListView_SortItems().

Add "Ex" to the names so that the new names will become

_GUICtrlListView_RegisterSortCallBackEx()

__GUICtrlListView_SortEx()

_GUICtrlListView_SortItemsEx().

Modify _GUICtrlListView_RegisterSortCallBackEx() to use __GUICtrlListView_SortEx in stead of __GUICtrlListView_Sort. __GUICtrlListView_SortEx() is the new callback function.

Modify _GUICtrlListView_SortItemsEx() to send a $LVM_SORTITEMSEX message in stead of a $LVM_SORTITEMS message. The $LVM_SORTITEMSEX message provides the item index in the $nItem1 and $nItem2 parameters of the callback function in stead of the item param provided by the $LVM_SORTITEMS message. Using $LVM_SORTITEMSEX you can skip the calculation of the index from the param.

There are more modifications to __GUICtrlListView_SortEx(). The first half of the modifications is just to delete the code used to calculate the index from the param. The second half of the modifications is to add the code to do the sorting.

An example is provided in the zip. Run SortListView.au3. The columns are sorted properly by strings, by numbers and by dates. The other file in the zip SortListViewFuncs.au3 contains the modified sort functions.

LarsJ.

The zip can be opened with 7-Zip.

SortListView.zip

Edited by LarsJ
Link to comment
Share on other sites

Hi jcpetu,

I understand your problems with sorting of the ListView. If you are using a native ListView you can register your own sorting callback function with GUICtrlRegisterListViewSort(). But if you are creating ListView's with the functions in GuiListView.au3 it's apparently not possible to use your own callback function with _GUICtrlListView_RegisterSortCallBack().

It's absolutely possible to sort a LV when using the UDF functions to create the items in the listview, you just have to know what you're doing when creating the items.

Here's the same example that I posted above, but using the UDF functions to add items to the listview instead of the native function.

#include <GUIConstantsEx.au3>
#include <GUIListView.au3>
$gui = GUICreate("Listview sorter")
$idListView = GUICtrlCreateListView("Column 1|Column 2", 10, 10, 300, 300)
$hListView = GUICtrlGetHandle($idListView)
For $I = 1 To 10
     _GUICtrlListView_AddItem($hListView, $I * Random(1, 100, 1), -1, $I + 1000) ; <<<<<<<<<<<< add 1000 to the item $iParam so it will sort
     _GUICtrlListView_AddSubItem($hListView, $I - 1, $I * Random(1, 100, 1), 1)
Next
GUISetState()
_GUICtrlListView_RegisterSortCallBack($hListView)
While 1
     $msg = GUIGetMsg()
     Switch $msg
          Case $GUI_Event_CLose
               _GUICtrlListView_UnRegisterSortCallBack($hListView)
               Exit
          Case $idListView
               sortLV()
     EndSwitch
WEnd
Func sortLV()
     Local $iCol = GUICtrlGetState($idListView)
     _GUICtrlListView_BeginUpdate($hListView)
     _GUICtrlListView_SortItems($hListView, $iCol)
     _GUICtrlListView_EndUpdate($hListView)
EndFunc   ;==>sortLV

BTW, if all you need is the column # for your custom sort routine, this line "Local $iCol = GUICtrlGetState($idListView)" will get the column number that was clicked.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

Hi BrewManNH,

I'm certainly not saying that you can't sort a LV using UDF functions. I'm saying that you can't supply a callback funtions without modifying the sort functions.

This is the parameters for _GUICtrlListView_RegisterSortCallBack:

_GUICtrlListView_RegisterSortCallBack( $hWnd [, $fNumbers = True [, $fArrows = True]] )

Where will you supply the callback function?

Show me how to sort the example in the help file for _GUICtrlListView_RegisterSortCallBack properly by date in the third column.

With GUICtrlRegisterListViewSort() for native LV's you can supply a callback function:

GUICtrlRegisterListViewSort( controlID, "function" ).

LarsJ.

Edited by LarsJ
Link to comment
Share on other sites

Here's example2 from the GUICtrlRegisterListViewSort example scripts showing that it's still quite possible to use that function in conjunction with UDF created items in a listview. I haven't altered anything other than removing example1 and the create item function that was included in the example. No alteration of the sort routine that is in the help file was done at all. I'll admit, it sometimes takes 2 clicks on the header to get it to sort, not sure why, but since this is only a proof-of-concept script I'm not going to get into figuring out why it does that.

#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <GUIListview.au3>
Global $nCurCol = -1
Global $nSortDir = 1
Global $bSet = 0
Global $nCol = -1

;~ Example1()
Example2()

; *******************************************************
; Example 1 - sorting 3 column's different
; *******************************************************

; Our sorting callback funtion
Func LVSort($hWnd, $nItem1, $nItem2, $nColumn)
    Local $val1, $val2, $nResult

    ; Switch the sorting direction
    If $nColumn = $nCurCol Then
        If Not $bSet Then
            $nSortDir = $nSortDir * - 1
            $bSet = 1
        EndIf
    Else
        $nSortDir = 1
    EndIf
    $nCol = $nColumn

    $val1 = GetSubItemText($hWnd, $nItem1, $nColumn)
    $val2 = GetSubItemText($hWnd, $nItem2, $nColumn)

    ; If it is the 3rd colum (column starts with 0) then compare the dates
    If $nColumn = 2 Then
        $val1 = StringRight($val1, 4) & StringMid($val1, 4, 2) & StringLeft($val1, 2)
        $val2 = StringRight($val2, 4) & StringMid($val2, 4, 2) & StringLeft($val2, 2)
    EndIf

    $nResult = 0 ; No change of item1 and item2 positions

    If $val1 < $val2 Then
        $nResult = -1 ; Put item2 before item1
    ElseIf $val1 > $val2 Then
        $nResult = 1 ; Put item2 behind item1
    EndIf

    $nResult = $nResult * $nSortDir

    Return $nResult
EndFunc   ;==>LVSort


; Retrieve the text of a listview item in a specified column
Func GetSubItemText($nCtrlID, $nItemID, $nColumn)
    Local $stLvfi = DllStructCreate("uint;ptr;int;int[2];int")
    Local $nIndex, $stBuffer, $stLvi, $sItemText

    DllStructSetData($stLvfi, 1, $LVFI_PARAM)
    DllStructSetData($stLvfi, 3, $nItemID)

    $stBuffer = DllStructCreate("char[260]")

    $nIndex = GUICtrlSendMsg($nCtrlID, $LVM_FINDITEM, -1, DllStructGetPtr($stLvfi));

    $stLvi = DllStructCreate("uint;int;int;uint;uint;ptr;int;int;int;int")

    DllStructSetData($stLvi, 1, $LVIF_TEXT)
    DllStructSetData($stLvi, 2, $nIndex)
    DllStructSetData($stLvi, 3, $nColumn)
    DllStructSetData($stLvi, 6, DllStructGetPtr($stBuffer))
    DllStructSetData($stLvi, 7, 260)

    GUICtrlSendMsg($nCtrlID, $LVM_GETITEMA, 0, DllStructGetPtr($stLvi));

    $sItemText = DllStructGetData($stBuffer, 1)

    $stLvi = 0
    $stLvfi = 0
    $stBuffer = 0

    Return $sItemText
EndFunc   ;==>GetSubItemText


; *******************************************************
; Example 2 - sorting with selfcreated items by DllCall
; *******************************************************
Func Example2()
    Local $hGUI, $lv, $msg

    $nCurCol = -1
    $nSortDir = 1
    $bSet = 0
    $nCol = -1

    $hGUI = GUICreate("Test", 300, 200)

    $lv = GUICtrlCreateListView("Column1|Col2|Col3", 10, 10, 280, 180)
    GUICtrlRegisterListViewSort(-1, "LVSort2") ; Register the function "SortLV" for the sorting callback

    _GUICtrlListView_AddItem($lv,"ABC",  -1, 1001)
    _GUICtrlListView_AddSubItem($lv, 0, "666", 1)
    _GUICtrlListView_AddSubItem($lv, 0, "10.05.2004", 2)
    _GUICtrlListView_AddItem($lv,"DEF", -1, 1002)
    _GUICtrlListView_AddSubItem($lv, 1, "444", 1)
    _GUICtrlListView_AddSubItem($lv, 1, "11.05.2005", 2)
    _GUICtrlListView_AddItem($lv,"CDE",  -1, 1003)
    _GUICtrlListView_AddSubItem($lv, 2, "444", 1)
    _GUICtrlListView_AddSubItem($lv, 2, "12.05.2004", 2)
    For $i = 0 To 2
        GUICtrlSendMsg($lv, $LVM_SETCOLUMNWIDTH, $i, -1)
        GUICtrlSendMsg($lv, $LVM_SETCOLUMNWIDTH, $i, -2)
    Next

    GUISetState()

    While 1
        $msg = GUIGetMsg()
        Switch $msg
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $lv
                $bSet = 0
                $nCurCol = $nCol
                GUICtrlSendMsg($lv, $LVM_SETSELECTEDCOLUMN, GUICtrlGetState($lv), 0)
                DllCall("user32.dll", "int", "InvalidateRect", "hwnd", ControlGetHandle($hGUI, "", $lv), "int", 0, "int", 1)
        EndSwitch
    WEnd
EndFunc   ;==>Example2

; Our sorting callback funtion
Func LVSort2($hWnd, $nItem1, $nItem2, $nColumn)
    Local $val1, $val2, $nResult

    ; Switch the sorting direction
    If $nColumn = $nCurCol Then
        If Not $bSet Then
            $nSortDir = $nSortDir * - 1
            $bSet = 1
        EndIf
    Else
        $nSortDir = 1
    EndIf
    $nCol = $nColumn

    $val1 = GetSubItemText($hWnd, $nItem1, $nColumn)
    $val2 = GetSubItemText($hWnd, $nItem2, $nColumn)

    ; If it is the 3rd colum (column starts with 0) then compare the dates
    If $nColumn = 2 Then
        $val1 = StringRight($val1, 4) & StringMid($val1, 4, 2) & StringLeft($val1, 2)
        $val2 = StringRight($val2, 4) & StringMid($val2, 4, 2) & StringLeft($val2, 2)
    EndIf

    $nResult = 0 ; No change of item1 and item2 positions

    If $val1 < $val2 Then
        $nResult = -1 ; Put item2 before item1
    ElseIf $val1 > $val2 Then
        $nResult = 1 ; Put item2 behind item1
    EndIf

    $nResult = $nResult * $nSortDir

    Return $nResult
EndFunc   ;==>LVSort2


; Retrieve the text of a listview item in a specified column
Func GetSubItemText2($nCtrlID, $nItemID, $nColumn)
    Local $stLvfi = DllStructCreate("uint;ptr;int;int[2];int")
    Local $stBuffer, $nIndex, $stLvi, $sItemText

    DllStructSetData($stLvfi, 1, $LVFI_PARAM) ; Find the item by our saved index
    DllStructSetData($stLvfi, 3, $nItemID)

    $stBuffer = DllStructCreate("char[260]")

    $nIndex = GUICtrlSendMsg($nCtrlID, $LVM_FINDITEM, -1, DllStructGetPtr($stLvfi));

    $stLvi = DllStructCreate("uint;int;int;uint;uint;ptr;int;int;int;int")

    DllStructSetData($stLvi, 1, $LVIF_TEXT)
    DllStructSetData($stLvi, 2, $nIndex)
    DllStructSetData($stLvi, 3, $nColumn)
    DllStructSetData($stLvi, 6, DllStructGetPtr($stBuffer))
    DllStructSetData($stLvi, 7, 260)

    GUICtrlSendMsg($nCtrlID, $LVM_GETITEMA, 0, DllStructGetPtr($stLvi));

    $sItemText = DllStructGetData($stBuffer, 1)

    $stLvi = 0
    $stLvfi = 0
    $stBuffer = 0

    Return $sItemText
EndFunc   ;==>GetSubItemText2

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...