Problem
I am trying to sort a list view with checkboxes in descending order. The _GUICtrlListView_SimpleSort function works as intended but upon first sort if all the checkboxes are uncheck when the sort is complete the item that was at index 0 is checked. This seems to be a problem when __GUICtrlListView_GetCheckedIndices used by the simplesort returns a blank\empty result.
It's not often I look at the default includes, I'm normally just happy functions work but there is some code in the sorting function in GuiListView.au3 that checks for comparision and if the items match then the checked state is set to True,
This comparison is correct as ithe first index (0) matches the __GUICtrlListView_GetCheckedIndices returned string (blank seen as 0) to it is assumed that the checkbox is to be selected.
The __GUICtrlListView_GetCheckedIndices seems to be longer than required and uses Redim inside a loop which, from information picked up on the forum, is a not ideal. I have searched on the bug tracker for tickets related to _GUICtrlListView_SimpleSort and they're all closed and the latest beta performs the same, so this may not be a problem. I know that _GUICtrlListView_RegisterSortCallBack sorts checkbox items correctly and the checked state remain the same but this would mean more code and probably my own sorting function to sort desecending by default.
My Solution
I have used the simplesort example from the help file and removed code I don't need and have also added __GUICtrlListView_SimpleSort to enable use of a shortened _GUICtrlListView_GetCheckedIndices that does not alter the checkbox state when sorting.
#include <GUIConstantsEx.au3> #include <GuiListView.au3> #include <WindowsConstants.au3> $Debug_LV = False ; Check ClassName being passed to ListView functions, set to True and use a handle to another control to see it work Global $hListView _Main() Func _Main() GUICreate("ListView SimpleSort", 400, 300) $hListView = GUICtrlCreateListView("col1|col2|col3", 2, 2, 394, 268) GUICtrlSendMsg($hListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES) GUICtrlSendMsg($hListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_FULLROWSELECT, $LVS_EX_FULLROWSELECT) GUICtrlSendMsg($hListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_CHECKBOXES, $LVS_EX_CHECKBOXES) ; added GUICtrlCreateListViewItem("line4|5|more_a", $hListView) GUICtrlCreateListViewItem("line5|4.50 |more_c", $hListView) GUICtrlCreateListViewItem("line5|4.0 |more_c", $hListView) GUICtrlCreateListViewItem("line3|23|more_e", $hListView) GUICtrlCreateListViewItem("line2|0.34560 |more_d", $hListView) GUICtrlCreateListViewItem("line1|1.0 |more_b", $hListView) GUICtrlCreateListViewItem("line1|0.1 |more_b", $hListView) GUICtrlCreateListViewItem("line1|10|more_b", $hListView) _GUICtrlListView_SetColumnWidth($hListView, 0, 75) _GUICtrlListView_SetColumnWidth($hListView, 1, 75) _GUICtrlListView_SetColumnWidth($hListView, 2, 75) GUISetState() GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") Global $B_DESCENDING[_GUICtrlListView_GetColumnCount($hListView)] ; Loop until user exits Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete() EndFunc ;==>_Main Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam) #forceref $hWnd, $iMsg, $iwParam Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView, $tInfo $hWndListView = $hListView If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView) $tNMHDR = DllStructCreate($tagNMHDR, $ilParam) $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom")) $iIDFrom = DllStructGetData($tNMHDR, "IDFrom") $iCode = DllStructGetData($tNMHDR, "Code") Switch $hWndFrom Case $hWndListView Switch $iCode Case $LVN_COLUMNCLICK ; A column was clicked $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam) ;~ _GUICtrlListView_SimpleSort($hWndListView, $B_DESCENDING, DllStructGetData($tInfo, "SubItem")) ; original help file line __GUICtrlListView_SimpleSort($hWndListView, $B_DESCENDING, DllStructGetData($tInfo, "SubItem")) ; line to use reworked function EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY ; #FUNCTION# ==================================================================================================================== ; Name...........: _GUICtrlListView_SimpleSort ; Description ...: Sorts a list-view control (limited) ; Syntax.........: _GUICtrlListView_SimpleSort($hWnd, ByRef $vDescending, $iCol) ; Parameters ....: $hWnd - Handle to the control ; $vDescending - Can be: ; | True - Sort Descending ; | False - Sort Ascending ; +Array - With the following format: ; |[0] - First Column ; |[1] - Second Column ; |[n] - Last Column ; $iCol - Column number ; Return values .: None ; Author ........: Gary Frost (gafrost) ; Modified.......: ; Remarks .......: This is a basic sort fuction, for advanced sort see GUICtrlRegisterListViewSort ; Related .......: GUICtrlRegisterListViewSort ; Link ..........: ; Example .......: Yes ; =============================================================================================================================== Func __GUICtrlListView_SimpleSort($hWnd, ByRef $vDescending, $iCol) If $Debug_LV Then __UDF_ValidateClassName($hWnd, $__LISTVIEWCONSTANT_ClassName) If _GUICtrlListView_GetItemCount($hWnd) Then Local $b_desc If (IsArray($vDescending)) Then $b_desc = $vDescending[$iCol] Else $b_desc = $vDescending EndIf Local $columns = _GUICtrlListView_GetColumnCount($hWnd) Local $items = _GUICtrlListView_GetItemCount($hWnd) Local $temp_item = "" Local $SeparatorChar = Opt('GUIDataSeparatorChar') For $x = 1 To $columns $temp_item = $temp_item & " " & $SeparatorChar Next $temp_item = StringTrimRight($temp_item, 1) Local $a_lv[$items][$columns + 1] Local $i_selected = StringSplit(_GUICtrlListView_GetSelectedIndices($hWnd), $SeparatorChar) Local $i_checked = _GUICtrlListView_GetCheckedIndices($hWnd, $SeparatorChar) ; new line ;~ Local $i_checked = StringSplit(__GUICtrlListView_GetCheckedIndices($hWnd), $SeparatorChar) ; UDF line Local $v_item, $iFocused = -1 For $x = 0 To UBound($a_lv) - 1 Step 1 If $iFocused = -1 Then If _GUICtrlListView_GetItemFocused($hWnd, $x) Then $iFocused = $x EndIf _GUICtrlListView_SetItemSelected($hWnd, $x, False) _GUICtrlListView_SetItemChecked($hWnd, $x, False) For $Y = 0 To UBound($a_lv, 2) - 2 Step 1 $v_item = StringStripWS(_GUICtrlListView_GetItemText($hWnd, $x, $Y), 2) If (StringIsFloat($v_item) Or StringIsInt($v_item)) Then $a_lv[$x][$Y] = Number($v_item) Else $a_lv[$x][$Y] = $v_item EndIf Next $a_lv[$x][$Y] = $x Next _ArraySort($a_lv, $b_desc, 0, 0, $iCol) For $x = 0 To UBound($a_lv) - 1 Step 1 For $Y = 0 To UBound($a_lv, 2) - 2 Step 1 _GUICtrlListView_SetItemText($hWnd, $x, $a_lv[$x][$Y], $Y) Next For $Z = 1 To $i_selected[0] If $a_lv[$x][UBound($a_lv, 2) - 1] = $i_selected[$Z] Then If $a_lv[$x][UBound($a_lv, 2) - 1] = $iFocused Then _GUICtrlListView_SetItemSelected($hWnd, $x, True, True) Else _GUICtrlListView_SetItemSelected($hWnd, $x, True) EndIf ExitLoop EndIf Next For $Z = 1 To $i_checked[0] If $a_lv[$x][UBound($a_lv, 2) - 1] = $i_checked[$Z] Then _GUICtrlListView_SetItemChecked($hWnd, $x, True) ExitLoop EndIf Next Next If (IsArray($vDescending)) Then $vDescending[$iCol] = Not $b_desc Else $vDescending = Not $b_desc EndIf EndIf EndFunc ;==>__GUICtrlListView_SimpleSort Func _GUICtrlListView_GetCheckedIndices($hWnd, $sDelim) If $Debug_LV Then __UDF_ValidateClassName($hWnd, $__LISTVIEWCONSTANT_ClassName) Local $aIndices[1] = [0] ; empty array for return if no items checked Local $sIndices = '' For $i = 0 To _GUICtrlListView_GetItemCount($hWnd) - 1 If _GUICtrlListView_GetItemChecked($hWnd, $i) Then $sIndices &= $i & $sDelim Next If Not $sIndices Then Return $aIndices ; return the empty array if the string is blank Return StringSplit(StringTrimRight($sIndices, StringLen($sDelim)), $sDelim) EndFunc ;==>_GUICtrlListView_GetCheckedIndices
If there is a better way to do the above using the standard includes?. Searching the forum I found guiness has done a similar function to get checked states here http://www.autoitscript.com/forum/topic/148874-count-listview-checked-items/?p=1059439 and based mine on his.
Question
What are the reasons for sending an array as the $B_DESCENDING parameter rather than True\False
Thanks