Listview sortieren nach anklicken einer Spalte

  • Hallo zusammen,

    ich habe mit ISN-Studio ein Formular $frmMain erstellt, in dem sich auch ein Listview $lstDebitoren befindet.
    Das Füllen des Listview (Daten kommen aus einer SQLite-DB) nach Eingabe in das Inputfeld $txtKundensuche klappt auch.

    Nun soll nach Anklicken eines Spaltenkopfes das Listview nach dieser Spalte sortiert werden.

    Im Debugging erhalte ich keine Fehlermeldung, mein Listview flimmert nach Klick auf einen Spaltenkopf nur kurz, der Pfeil ändert seine Richtung, es wird aber nicht sortiert.

    Die Datei Equipments.au3 habe ich angehängt.

    Vielen Dank für Eure Unterstützung!


    Grüsse, Mike

    • Offizieller Beitrag

    Bsp.:

    Spoiler anzeigen
    [autoit]

    #include <WindowsConstants.au3>
    #include <ListViewConstants.au3>
    #include <GuiConstantsEx.au3>
    #include <GuiListView.au3>

    [/autoit] [autoit][/autoit] [autoit]

    GUICreate("ListView SimpleSort by Column Click", 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)
    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()

    [/autoit] [autoit][/autoit] [autoit]

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    Global $B_DESCENDING[_GUICtrlListView_GetColumnCount($hListView)]

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
    GUIDelete()

    [/autoit] [autoit][/autoit] [autoit]

    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)

    [/autoit] [autoit][/autoit] [autoit]

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    If ($hWndFrom = $hWndListView) And ($iCode = $LVN_COLUMNCLICK) Then
    $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
    _GUICtrlListView_SimpleSort($hWndListView, $B_DESCENDING, DllStructGetData($tInfo, "SubItem"))
    ;~ _GUICtrlListView_SimpleSort($hWndListView, $B_DESCENDING, DllStructGetData($tInfo, "SubItem"), False) ; kein Toggle
    EndIf
    EndFunc ;==>WM_NOTIFY

    [/autoit]
  • Hi BugFix,

    vielen Dank, es klappt perfekt :)

    Noch zwei Fragen:

    - Warum werden diese kleinen Pfeile für die Sortierrichtung nun nicht mehr angezeigt?
    - Wie muß ich die Funktion erweitern, um mehrere Listviews damit sortieren zu können? ---> GELÖST :)

    Viele Grüsse, Mike

    Einmal editiert, zuletzt von mausk (20. August 2014 um 15:46)

  • Hi Xenobiologist,

    danke für Deine schnelle Antwort.

    Und wo und wie baue ich _GUICtrlListView_RegisterSortCallBack in mein Skript ein???

    Viele Grüsse, Mike

  • Ich mache das immer so:

    Spoiler anzeigen
    [autoit]


    #include <ButtonConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <HeaderConstants.au3>
    #include <ListViewConstants.au3>
    #include <WindowsConstants.au3>
    #include <Guilistview.au3>
    #include <File.au3>
    #include <Array.au3>
    #include <SendMessage.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ; nuts (http://www.autoit.de)

    [/autoit] [autoit][/autoit] [autoit]

    Global $nSortDir = 1
    #Region ### START Koda GUI section ### Form=
    Global $Form1 = GUICreate("Form1", 633, 544, 193, 125)
    Global $ListView1 = GUICtrlCreateListView("0|1|2|3", 48, 16, 521, 385)
    GUICtrlRegisterListViewSort(-1, "_LVSort")
    Global $hLVHandle = GUICtrlGetHandle($ListView1)
    _GUICtrlListView_SetColumn($hLVHandle, 0, "Text", 50, 1)
    _GUICtrlListView_SetColumn($hLVHandle, 1, "Nummer", 150, 1)
    _GUICtrlListView_SetColumn($hLVHandle, 2, "Datum1", 150, 1)
    _GUICtrlListView_SetColumn($hLVHandle, 3, "Datum2", 150, 1)
    Global $Button1 = GUICtrlCreateButton("Test", 216, 448, 177, 49, 0)
    GUISetState(@SW_SHOW)
    #EndRegion ### END Koda GUI section ###

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To 20
    $temp = Random(1, 31, 1)
    If $temp < 10 Then $temp = "0" & $temp
    GUICtrlCreateListViewItem("ABC|" & Random(1, 10050, 1) & "|2010\02" & $temp & "|" & $temp & ".02.2010", $ListView1)
    GUICtrlCreateListViewItem("DDC|" & Random(1, 10050, 1) & "|2011\03" & $temp & "|" & $temp & ".03.2011", $ListView1)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Global $hSORTCALLBACK = DllCallbackRegister("_LV_SortCallback", "Handle", "LPARAM;LPARAM;LPARAM")
    Global $pSORTCALLBACK = DllCallbackGetPtr($hSORTCALLBACK)

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    Case $Button1
    ;sortiere nach col 2
    _LV_SortColumn($ListView1, $pSORTCALLBACK, 2)
    $nSortDir = $nSortDir * - 1
    Case $ListView1
    ; DllCall("user32.dll", "int", "InvalidateRect", "hwnd", $hLVHandle, "int", 0, "int", 1)
    $nSortDir = $nSortDir * - 1
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _LV_SortColumn($idLV, $pCallbackProc, $iCol)
    ; Der Spaltenindex wird 1-basiert erwartet !!!
    Local $Result = GUICtrlSendMsg($idLV, $LVM_SORTITEMS, $iCol - 1, $pCallbackProc)
    Return $Result
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _LV_SortCallback($Item1, $Item2, $Col)
    Return _LVSort($ListView1, $Item1, $Item2, $Col)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _Sort_byNumber($item1, $item2)

    [/autoit] [autoit][/autoit] [autoit]

    Local $ret = 0

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    If Number($item1) < Number($item2) Then
    $ret = -1
    ElseIf Number($item1) > Number($item2) Then
    $ret = 1

    [/autoit] [autoit][/autoit] [autoit]

    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Return $ret

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_Sort_byNumber

    [/autoit] [autoit][/autoit] [autoit]

    Func _Sort_byString($item1, $item2)
    Local $ret = 0

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    If $item1 < $item2 Then
    $ret = -1
    ElseIf $item1 > $item2 Then
    $ret = 1

    [/autoit] [autoit][/autoit] [autoit]

    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Return $ret
    EndFunc ;==>_Sort_byString

    [/autoit] [autoit][/autoit] [autoit]

    Func _Sort_byDate($item1, $item2, $del = ".", $step = -1)

    [/autoit] [autoit][/autoit] [autoit]

    Local $ret = 0, $sitem1, $sitem2, $aitem1, $aitem2

    [/autoit] [autoit][/autoit] [autoit]

    $aitem1 = StringSplit($item1, $del)
    $aitem2 = StringSplit($item2, $del)
    Switch $step
    Case - 1
    For $i = $aitem1[0] To 1 Step -1
    $sitem1 &= $aitem1[$i]
    Next
    For $i = $aitem2[0] To 1 Step -1
    $sitem2 &= $aitem2[$i]
    Next
    Case 1
    For $i = 1 To $aitem1[0]
    $sitem1 &= $aitem1[$i]
    Next
    For $i = 1 To $aitem2[0]
    $sitem2 &= $aitem2[$i]
    Next
    EndSwitch

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;ConsoleWrite($sitem1 & " | "& $sitem2 & " | $val1 < $val2"&@CRLF) ;debug

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    If Number($sitem1) < Number($sitem2) Then
    $ret = -1
    ElseIf Number($sitem1) > Number($sitem2) Then
    $ret = 1

    [/autoit] [autoit][/autoit] [autoit]

    EndIf

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Return $ret

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_Sort_byDate

    [/autoit] [autoit][/autoit] [autoit]

    Func _LVSort($hWnd, $nItem1, $nItem2, $nColumn)
    Local $val1, $val2, $nResult

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

    ;ConsoleWrite($val1 & " | "& $val2 & " | $val1 < $val2"&@CRLF) ;debug

    [/autoit] [autoit][/autoit] [autoit]

    $nResult = 0

    [/autoit] [autoit][/autoit] [autoit]

    Switch $nColumn

    [/autoit] [autoit][/autoit] [autoit]

    Case 3
    $nResult = _Sort_byDate($val1, $val2)
    Case 2

    [/autoit] [autoit][/autoit] [autoit]

    $nResult = _Sort_byDate($val1, $val2, "", 1)
    Case 1
    $nResult = _Sort_byNumber($val1, $val2)
    Case 0
    $nResult = _Sort_byString($val1, $val2)

    [/autoit] [autoit][/autoit] [autoit]

    EndSwitch
    $nResult = $nResult * $nSortDir
    Return $nResult

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_LVSort

    [/autoit] [autoit][/autoit] [autoit]

    Func GetSubItemText($nCtrlID, $nItemID, $nColumn)
    Local $stLvfi = DllStructCreate("uint;ptr;int;int[2];int")
    Local $nIndex, $stBuffer, $stLvi, $sItemText

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

    $sItemText = DllStructGetData($stBuffer, 1)

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

    Return $sItemText
    EndFunc ;==>GetSubItemText

    [/autoit]

    Damit lässt sich die Funktion wie sortiert werden soll beliebig an den Inhalt des Listviews anpassen.

  • Hi nuts,

    danke für Deine Antwort, aber ich möchte mein (funktionierendes) Skript nicht durch einen Eingabefehler von mir zerstören :)
    Es geht mir wie gesagt nur noch um die kleinen Pfeile in den Spaltenköpfen, die bei mir nicht mehr angezeigt werden.

    Vielen Dank und Grüsse

  • Dazu musst du "_GUICtrlListView_RegisterSortCallBack" und "_GUICtrlListView_SortItems" (s. Hilfe für Beispiele) für die Sortierung verwenden.

    Oder diesen Teil auf dein Skript übertragen:

    [autoit]

    Func _GUICtrlListView_SortItems($hWnd, $iCol)
    Local $iRet, $iIndex, $pFunction, $hHeader, $iFormat

    [/autoit][autoit][/autoit][autoit]

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

    [/autoit][autoit][/autoit][autoit]

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

    [/autoit][autoit][/autoit][autoit]

    $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
    $iRet = _SendMessage($hWnd, $LVM_SORTITEMS, $hWnd, $pFunction, 0, "hwnd", "ptr")
    If $iRet <> 0 Then
    If $aListViewSortInfo[$iIndex][9] Then ; Use arrow in header ; ab hier
    $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))
    Else ; descending
    _GUICtrlHeader_SetItemFormat($hHeader, $iCol, BitOR($iFormat, $HDF_SORTDOWN))
    EndIf
    EndIf
    EndIf

    [/autoit][autoit][/autoit][autoit]

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

    [/autoit]