Listview sortieren ohne Columnclick

  • Hallo zusammen,

    folgendes Problem:
    Ich möchte ein Listview nach verschiedenen Kriterien sortieren.

    Dazu verwende ich GUICtrlRegisterListViewSort
    Das funktioniert auch wunderbar.

    Nun möchte ich diese Sortierfunktion auf einem anderen Weg starten (Hotkey, Buttonclick usw.)

    Hier mal ein Beispiel zum spielen:

    Spoiler anzeigen
    [autoit]


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

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

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

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

    Global $nSortDir = 1

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

    #Region ### START Koda GUI section ### Form=
    Global $Form1 = GUICreate("Form1", 633, 544, 193, 125)
    Global $ListView1 = GUICtrlCreateListView("Text|Nummer|Datum1|Datum2", 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)

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

    Global $Button1 = GUICtrlCreateButton("Test", 216, 448, 177, 49, 0)
    GUISetState(@SW_SHOW)
    #EndRegion ### END Koda GUI section ###

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

    For $i = 0 To 5
    $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)

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

    Next

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    Case $Button1
    ;sortiere nach col 2
    _SendMessage(0x00130458, 78, 0x00000003, 0x008CE2AC)
    $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][/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)

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

    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]


    Also z.B. eine Sortierung von Spalte 2 durch klicken des Buttons.


    Gruß nuts

    Einmal editiert, zuletzt von nuts (5. Juli 2012 um 21:08)

  • Das Handle deines listviews rausfinden und dann einfach bei Buttonclick _LVSort mit den Parametern ausführen

  • Ohne deinen Programmierdrang bremsen zu wollen, was hast Du gegen den ColumClick.
    So schreibst du für jede Spalte eine Funktion obwohl es auch so funktinieren würde?

    Gruß Dietmar

    Achtung Anfänger! :whistling:

    Betrachten des Quellcodes auf eigene Gefahr, bei Übelkeit,Erbrechen,Kopfschmerzen übernehme ich keine Haftung. 8o

  • Wie ist die Alternative?
    z.B.
    Spalte1: Datum: DD.MM.YYYY
    Spalte2: Zahlen von 1-10000
    Dazu muss ich doch jeweils eine andere Sortierfunktion verwenden?

    Ich möchte für bestimmte Spalten eben verschiedene Prüfschleifen (mit Sortierung) erstellen.
    Dazu bietet es sich an das Listview erstmal entsprechend zu sortieren.
    Die Prüfungen sollen eben nicht über die Header angestossen werden.

    TheLuBu: Das funktioniert nicht. (_LV_Sort gibt immer 0 für no change zurück und läuft auch nur einmal an)

  • Nein ich meine warum betreibst Du den Aufwand,
    man ist es doch von Excel etc gewöhnt das sich die Sortierung über die Spaltenkopfzeile ändern lässt
    und das geht ja quasi von Hause aus, zumindest mit den Erweiterungen von Bugfix.

    Gruß Dietmar

    Achtung Anfänger! :whistling:

    Betrachten des Quellcodes auf eigene Gefahr, bei Übelkeit,Erbrechen,Kopfschmerzen übernehme ich keine Haftung. 8o

  • Ich bin etwas aus der Übung und verstehe nicht so ganz was zu mir sagen willst - sorry! :(

    Die normale Funkionalität (Sortierung über Spaltenkopfzeile) bleibt bei mir auch erhalten.
    Um nach verschiedenen Kriterien zu sortieren (Col1 -> Datum, Col2 0-n, Col3 ABC usw.) bleibt doch nur der Weg über GUICtrlRegisterListViewSort und entsprechend unterschiedlichen Funktionen für die Art und Weise der Sortierung.

    Für die Prüfschleifen bietet es sich jedoch an gleich mit der Sortierung zu beginnen. Nur ohne Mausklick auf den header bekomm ich die nicht in gang.

  • Moin,

    man kann auch mit der Nachricht LVM_SORTITEMEX eine Sortierung anstoßen und dabei in lParam eine eigene Callbackfunktion und in wParam z.B. die Spalte übergeben. Ich habe das schon mal umgesetzt, komme aber jetzt nicht an den Code heran.

  • ... ja, nur temporär.

    Ich habe mal ein schlichtes Beispiel in Dein Skript eingebaut, allerdings mit LVM_SORTITEMS ohne EX, weil es dann besser zu Deinen Funktionen passt:

    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]


    Es müsste auch mit _GUICtrlListView_RegisterSortCallBack() und _GUICtrlListView_SortItems() gehen, dann wird für die Sortierung wohl __GUICtrlListView_Sort() genutzt.

  • Na super! Das löst mein Problem doch! Danke :thumbup:

    Zitat


    Es müsste auch mit _GUICtrlListView_RegisterSortCallBack() und _GUICtrlListView_SortItems() gehen, dann wird für die Sortierung wohl __GUICtrlListView_Sort() genutzt.


    Das stimmt.
    Nach genauerem Untersuchen ist mir aber aufgefallen, dass es für die Sortierfunktion ja eine eigene Funktion (__GUICtrlListView_Sort($nItem1, $nItem2, $hWnd) nur interne verwendung) in der Guilistview.au3 UDF gibt.
    Diese lässt sich theoretisch auch anpassen.

    Aber deine Lösung klappt ja auch! :)


    Edit\ DllCallbackFree sollte man beim beenden noch ausführen oder ist das in dem Fall nicht nötig?

    Einmal editiert, zuletzt von nuts (8. April 2011 um 10:11)