Sign in to follow this  
Followers 0
jcpetu

How to detect sort finish

14 posts in this topic

Hi people, I got a ListView defined with a couple of functions trigger to sort items as follow:

$MMenuLVAD = GUICtrlCreateListView("", 3, 132, $MainGuiW - 5, $MainGuiH - 180, -1, BitOR($LVS_EX_CHECKBOXES, $LVS_EX_FULLROWSELECT, $LVS_EX_HEADERDRAGDROP, $LVS_EX_GRIDLINES, $LVS_EX_DOUBLEBUFFER))
    GUICtrlSetOnEvent(-1, "Setsort") ; clicking the column header will start the sort
    GUICtrlRegisterListViewSort(-1, "LVSort") ; Register the function "SortLV" as the sorting callback

I added a Tooltip while in the sorting process like:

ToolTip("Sorting column", Default, Default, "Please wait", 1, 2)

But I don't know how to detect the sorting function had finished.

Any Help will be appreciated.

Share this post


Link to post
Share on other sites



Just to clarify. I need to detect when the sorting function finish to clear tooltip.

Func Setsort() ;Draw arrow on ListView Header

        ToolTip("Sorting column", Default, Default, "Please wait", 1, 2)

    $bSet = 0 ; initialize for new sorting
    GUICtrlSendMsg($MMenuLVAD, $LVM_SETSELECTEDCOLUMN, GUICtrlGetState($MMenuLVAD), 0) ; mark the sorted column with a grey rectangle
    DllCall("user32.dll", "int", "InvalidateRect", "hwnd", GUICtrlGetHandle($MMenuLVAD), "int", 0, "int", 1)
    Local $iFormat ; create an arrow in the listview header
    Local Const $hHeader = _GUICtrlListView_GetHeader($MMenuLVAD)
    For $x = 0 To _GUICtrlHeader_GetItemCount($hHeader) - 1 ; clear existing arrows
        $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
    Local $nColumn = GUICtrlGetState($MMenuLVAD) ; set arrow in current column
    $iFormat = _GUICtrlHeader_GetItemFormat($hHeader, $nColumn)
    If $nSortDir == 1 And $nCol == $nColumn Then
        _GUICtrlHeader_SetItemFormat($hHeader, $nColumn, BitOR($iFormat, $HDF_SORTUP));ascending
    Else
        _GUICtrlHeader_SetItemFormat($hHeader, $nColumn, BitOR($iFormat, $HDF_SORTDOWN));descending
    EndIf
EndFunc   ;==>Setsort

Func LVSort($hWnd, $nItem1, $nItem2, $nColumn) ;Sort List View
    Local $nSort, $val1, $val2, $nResult
    If Not $bSet Then
        If $nColumn = $nCol Then
            $nSortDir = -$nSortDir
        Else
            $nSortDir = 1
        EndIf
        $bSet = 1
    EndIf
    $nCol = $nColumn
    Switch $nColumn
        Case 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ; text
            $val1 = GetSubItemText($hWnd, $nItem1, $nColumn)
            $val2 = GetSubItemText($hWnd, $nItem2, $nColumn)
        EndSwitch
    Select
        Case $val1 < $val2
            $nResult = -1 ; Put item2 before item1
        Case $val1 > $val2
            $nResult = 1 ; Put item2 behind item1
    EndSelect
    $nResult = $nResult * $nSortDir
    ToolTip("")
    Return $nResult

EndFunc   ;==>LVSort

Thanks in advance for any help. :bye:

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

The call to ToolTip should be placed outside your 'LVSort' function. The function in the helpfile example is called recursively. This means your tooltip may disappear too early. I'm kind of guessing because the rest of your code is missing.

CODE REMOVED

Edited by czardas

Share this post


Link to post
Share on other sites

Hi czardas, I'll give it a try. Thanks a lot and regars.

Share this post


Link to post
Share on other sites

Czards, do you know if it is any way, from WMNotify, to know when the LVsort function finishes?

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Oops, I see my example isn't quite right because the normal loop is interrupted by the callback function. I removed the code from my previous post. I'm afraid I don't know of a way to determine if the sort has finished after using GUICtrlRegisterListViewSort. I tried but without success. I normally write my own functions for controls like ListViews. You could grab the ListView contents and sort them in an array. There may be a UDF function that will do what you want. If nobody else comes up with a solution, you could perhaps put in a feature request.

Edited by czardas

Share this post


Link to post
Share on other sites

Thanks a lot Czardas and regards.

Share this post


Link to post
Share on other sites

Have you tried it with the UDF sort functions?


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

Share this post


Link to post
Share on other sites

I only tried whith the attached UDF, what UDF sort function you meant?

Share this post


Link to post
Share on other sites

In the GUIListView.au3 UDF that comes with AutoIt, there are 2 functions that will sort the listview, _GUICtrlListView_SimpleSort and _GUICtrlListView_SortItems. The first one is easier to use, but the results may not be that great, and the second one is used with _GUICtrlListView_RegisterSortCallBack. Might be worth trying those to see if they're easier to tell when they've finished sorting.


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

Share this post


Link to post
Share on other sites

jcpetu, You can generate your own sort finished message with GUICtrlSendToDummy in the sorting function. Because AutoIt message loop is blocked while the sorting is going on, you'll not receive the message until the sorting is finished.

This is the first example for GUICtrlRegisterListViewSort in the help file with extra 10 lines of code to implement the sort finished message (listview extended to 300 rows):

; sorting 3 column's different

#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>

Global $idSortFinished, $fSortFinishedMsg = False
Global $nCurCol = -1
Global $nSortDir = 1
Global $bSet = 0
Global $nCol = -1

Example()

Func Example()
  Local $lv, $msg

  GUICreate("Test", 300, 200)

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

  For $i = 1 To 100 ; 300 rows to make it more realistic
    GUICtrlCreateListViewItem("ABC|666|10.05.2004", $lv)
    GUICtrlSetImage(-1, "shell32.dll", 7)
    GUICtrlCreateListViewItem("DEF|444|11.05.2005", $lv)
    GUICtrlSetImage(-1, "shell32.dll", 12)
    GUICtrlCreateListViewItem("CDE|444|12.05.2004", $lv)
    GUICtrlSetImage(-1, "shell32.dll", 3)
  Next

  GUISetState(@SW_SHOW)

  ; Loop until the user exits.
  Local $iSorts = 0
  While 1
    $msg = GUIGetMsg()
    Switch $msg
      Case $GUI_EVENT_CLOSE
        ExitLoop

      Case $idSortFinished
        $iSorts += 1
        ConsoleWrite( "$idSortFinished " & $iSorts & @CRLF )
        $fSortFinishedMsg = False

      Case $lv
        $bSet = 0
        $nCurCol = $nCol
        GUICtrlSendMsg($lv, $LVM_SETSELECTEDCOLUMN, GUICtrlGetState($lv), 0)
        DllCall("user32.dll", "int", "InvalidateRect", "hwnd", GUICtrlGetHandle($lv), "int", 0, "int", 1)
    EndSwitch
  WEnd

  GUIDelete()
EndFunc   ;==>Example

; Our sorting callback funtion
Func LVSort($hWnd, $nItem1, $nItem2, $nColumn)
  ConsoleWrite( "Sorting" & @CRLF )
  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
  If $fSortFinishedMsg Then Return $nResult

  GUICtrlSendToDummy( $idSortFinished )
  $fSortFinishedMsg = True
  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
Watch the sort finished messages in Scite console.

Share this post


Link to post
Share on other sites

BrewManNH, yes I tested this two function without success I will try now with LarsJ example.

Thanks a lot.

 

Hi LarsJ nice to hear from you again, I will modify it a bit cuz I got an onevent implementation.

Thanks a lot.

Share this post


Link to post
Share on other sites

@LarsJ

Nice example! My idea was use an Adlib e.g.

; sorting 3 column's different

#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>

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

Example()

Func Example()
  Local $lv, $msg

  GUICreate("Test", 300, 200)

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

  For $i = 1 To 100 ; 300 rows to make it more realistic
    GUICtrlCreateListViewItem("ABC|666|10.05.2004", $lv)
    GUICtrlSetImage(-1, "shell32.dll", 7)
    GUICtrlCreateListViewItem("DEF|444|11.05.2005", $lv)
    GUICtrlSetImage(-1, "shell32.dll", 12)
    GUICtrlCreateListViewItem("CDE|444|12.05.2004", $lv)
    GUICtrlSetImage(-1, "shell32.dll", 3)
  Next

  GUISetState(@SW_SHOW)

  ; Loop until the user exits.
  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", GUICtrlGetHandle($lv), "int", 0, "int", 1)
    EndSwitch
  WEnd

  GUIDelete()
EndFunc   ;==>Example

; Our sorting callback funtion
Func LVSort($hWnd, $nItem1, $nItem2, $nColumn)
  ConsoleWrite( "Sorting" & @CRLF )
  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

  AdlibRegister(_SortFinished)
  Return $nResult
EndFunc   ;==>LVSort

Func _SortFinished()
    AdlibUnRegister(_SortFinished)

    Static $iSorts = 0
    $iSorts += 1
    ConsoleWrite( "Sort finished " & $iSorts & @CRLF )
EndFunc

; 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

Pretty similar but 2 lines shorter ;)

Share this post


Link to post
Share on other sites

I already implemented the Tooltip for the function. 

THANKS a lot to all of you.

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  
Followers 0