ListView und Filter, nur wie am besten?

  • Hallo Zusammen,

    ich bin auf der Suche nach einer Möglichkeit, die Liste eines ListViews zu filtern bzw. darin zu suchen.

    Bisher bin ich mit meinem Lösungsansatz noch nicht ganz glücklich. Die gefundenen Zeilen sind nicht deutlich genug "markiert". Wie könnte ich das besser machen?

    Oder gibt es eine Möglichkeit, die nicht benötigten Zeilen auszublenden, ähnlich wie man es mit _GUICtrlListView_HideColumn für Spalten machen könnte? Dann blieben nur noch die zutreffenden Reihen übrig.

    Spoiler anzeigen
    [autoit]

    #Region ;**** Directives created by AutoIt3Wrapper_GUI ****
    #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
    #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
    #include <GuiConstantsEx.au3>
    #include <ButtonConstants.au3>
    #include <GuiListView.au3>
    #include <GuiImageList.au3>
    #include <array.au3>
    #include <Date.au3>

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

    Opt('MustDeclareVars', 1)

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

    $Debug_LV = False ; Check ClassName being passed to ListView functions, set to True and use a handle to another control to see it work

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

    #Region Vars-Declaration
    Global $MyGui, $GuiListView, $GuiFilterInput, $GuiStatusLabel, $GuiButtonFiltern, $GuiButtonClear, $GuiButtonLast, $GuiButtonNext, $GuiMSG, $hImage
    Global $GuiWidth = 700, $GuiHeight = 400 ; GUI-Größe
    Global $MaxRows = 999, $MaxCol = 5 ; Reihen und Spalten
    Global $FoundedArray, $FApos ; Hilfsarray für die gefundenen Elemente
    Global $MyInitTimer
    Global Const $ItemDistance = 10
    Global $LastX
    #EndRegion Vars-Declaration

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

    #Region Gui-Creation
    ; -- GUI erzeugen --
    $MyGui = GUICreate("Filter in ListView", $GuiWidth, $GuiHeight)
    $LastX = $ItemDistance
    GUICtrlCreateLabel("Filter:", $LastX, 20, 30, 20)
    $LastX += 30 + $ItemDistance
    $GuiFilterInput = GUICtrlCreateInput("99", $LastX, 20 - 3, 200)
    $LastX += 200 + $ItemDistance
    $GuiButtonFiltern = GUICtrlCreateButton("Filtern/Suchen", $LastX, 20 - 4, 90, 24, $BS_DEFPUSHBUTTON)
    $LastX += 90 + $ItemDistance
    $GuiButtonClear = GUICtrlCreateButton("Löschen", $LastX, 20 - 4, 90, 24)
    $LastX += 90 + $ItemDistance
    $GuiButtonLast = GUICtrlCreateButton("<<", $LastX, 20 - 4, 20, 24)
    GUICtrlSetState(-1, $GUI_DISABLE)
    $LastX += 20 + $ItemDistance
    $GuiButtonNext = GUICtrlCreateButton(">>", $LastX, 20 - 4, 20, 24)
    GUICtrlSetState(-1, $GUI_DISABLE)
    ; $GuiListView = GUICtrlCreateListView("", 10, 60, $GuiWidth - 20, 290, BitOR($LVS_SHOWSELALWAYS, $LVS_NOSORTHEADER), $LVS_EX_FULLROWSELECT)
    $GuiListView = GUICtrlCreateListView("", 10, 60, $GuiWidth - 20, 290, BitOR($LVS_SHOWSELALWAYS, $LVS_NOSORTHEADER), BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_CHECKBOXES))
    $GuiStatusLabel = GUICtrlCreateLabel("Gui erzeugen...", 10, $GuiHeight - 20, $GuiWidth - 20, 20)
    GUISetState(@SW_SHOW, $MyGui)
    #EndRegion Gui-Creation

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

    #Region fill the listview
    ; -- Tabelle füllen --
    $MyInitTimer = TimerInit()
    _GUICtrlListView_BeginUpdate($GuiListView)
    ; Add columns
    For $c = 1 To $MaxCol
    _GUICtrlListView_InsertColumn($GuiListView, $c - 1, "Column " & $c, 100)
    Next
    ; Add items
    SetStatus("Erzeugen (" & $MaxRows & " x " & $MaxCol & ")...", 1)
    For $r = 1 To $MaxRows
    _GUICtrlListView_AddItem($GuiListView, "Row " & $r & ", Col 1, " & Random(0, 99999, 1), $r - 1)
    For $c = 2 To $MaxCol
    _GUICtrlListView_AddSubItem($GuiListView, $r - 1, "Row " & $r & ", Col " & $c & ", " & Random(0, 99999, 1), $c - 1)
    Next
    Next
    _Debug("main", "Tabelle füllen", ru_TimerDiffNice($MyInitTimer))
    ; Spaltenbreite anpassen
    $MyInitTimer = TimerInit()
    For $c = 1 To $MaxCol
    _GUICtrlListView_SetColumnWidth($GuiListView, $c - 1, $LVSCW_AUTOSIZE)
    Next
    _Debug("main", "Spaltenbreite anpassen", ru_TimerDiffNice($MyInitTimer))
    _GUICtrlListView_EndUpdate($GuiListView)
    #EndRegion fill the listview

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

    #Region Main
    ; Mainloop
    SetStatus("")
    While 1
    $GuiMSG = GUIGetMsg()

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

    Switch $GuiMSG
    Case $GUI_EVENT_CLOSE ; Window-Event-Close
    GUISetState(@SW_HIDE, $MyGui)
    GUIDelete($MyGui)
    Exit

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

    Case $GuiButtonFiltern ; Filtern/Suchen
    Search(GUICtrlRead($GuiFilterInput))

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

    Case $GuiButtonClear ; clear filter
    GUICtrlSetData($GuiFilterInput, "")
    Search("")
    SetStatus("Filter gelöscht")

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

    Case $GuiButtonLast ; last
    JumpToFoundedItem(-1)

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

    Case $GuiButtonNext ; next
    JumpToFoundedItem(+1)
    EndSwitch
    WEnd
    #EndRegion Main

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

    #Region Funktionsdefinitionen
    ; Funktion, die im Listview nach dem Filter sucht und alle Zeilen markiert.
    ; Ebenfalls werden die gefundenen Rows im Array $FoundedArray aufgehoben, damit mit "last" und "next" umgeblättert werden kann
    Func Search($myFilter)
    Local $MyLocalInitTimer = TimerInit()
    Local $FoundInRow, $LastRow, $CounterFounded

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

    ; Filter-Eingabe
    ; $myFilter = InputBox("Bitte Filter eingeben", "Z.B. 99", 99, "", 200, 120)
    If $myFilter == "" Then
    ; Alle Selektionen entfernen
    _GUICtrlListView_SetItemSelected($GuiListView, -1, False, False) ; Alle entfernen
    ; Butto deaktivieren
    GUICtrlSetState($GuiButtonLast, $GUI_DISABLE)
    GUICtrlSetState($GuiButtonNext, $GUI_DISABLE)
    ; FoundedArray löschen
    $FoundedArray = "" ; Array
    $FApos = 0 ; Position im Array für "last" und "next"
    SetStatus("Alle anzeigen")
    Return
    EndIf

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

    ; Alle Selektionen entfernen
    _GUICtrlListView_SetItemSelected($GuiListView, -1, False, False) ; Alle entfernen

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

    ; Parameter zurücksetzen
    $FoundInRow = -1 ; start from the beginning
    $LastRow = -2
    $CounterFounded = 0

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

    ; Suchen
    _GUICtrlListView_BeginUpdate($GuiListView)
    SetStatus('Suchen nach "' & $myFilter & '"...', 1)
    ; Search for target item
    While 1
    $FoundInRow = _GUICtrlListView_FindInText($GuiListView, $myFilter, $FoundInRow)
    If $FoundInRow < 0 Or $LastRow >= $FoundInRow Then ExitLoop 1
    ; "Last" aufheben, damit nicht unendlich immer wieder von vorne gesucht wird
    $LastRow = $FoundInRow
    $CounterFounded += 1
    _GUICtrlListView_SetItemSelected($GuiListView, $FoundInRow, True, True) ; Nur den einen setzen
    ; _GUICtrlListView_SetItemState($GuiListView, $FoundInRow, $LVIS_SELECTED, $LVIS_SELECTED)
    ; _GUICtrlListView_EnsureVisible($GuiListView, $FoundInRow) ; Hinscrollen/Anzeigen
    WEnd
    _GUICtrlListView_EndUpdate($GuiListView)

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

    ; Ausgabe, diesmal mit _GUICtrlListView_GetSelectedCount
    ; SetStatus(_GUICtrlListView_GetSelectedCount($GuiListView) & ' Items mit "' & $myFilter & '" gefunden und markiert')

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

    ; Retrieve indices of selected item(s)
    $FoundedArray = _GUICtrlListView_GetSelectedIndices($GuiListView, True)
    ; _ArrayDisplay($FoundedArray, "founded items")
    $FApos = 0
    JumpToFoundedItem(+1)

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

    ; Button frei geben
    If IsArray($FoundedArray) And $FoundedArray[0] > 0 Then
    GUICtrlSetState($GuiButtonLast, $GUI_ENABLE)
    GUICtrlSetState($GuiButtonNext, $GUI_ENABLE)
    EndIf

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

    _Debug("Search", 'suchen nach "' & $myFilter & '"', ru_TimerDiffNice($MyLocalInitTimer))

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

    ; Ausgabe in MsgBox
    If $CounterFounded == 0 Then
    MsgBox(0, "Suchergebnis", 'Es wurden keine Items mit "' & $myFilter & '" gefunden!')
    Else
    MsgBox(0, "Suchergebnis", $CounterFounded & ' Items mit "' & $myFilter & '" gefunden und markiert')
    EndIf
    EndFunc ;==>Search

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

    ; Funktion, die in dem $FoundedArray von der derzeitigen Position im Array $FApos vor +der zurückblättert und an
    ; die betreffende Reihe springt
    ; $ArrayPos ist normalerweise +1 oder -1
    Func JumpToFoundedItem($ArrayPos = 0)
    Local $MyLocalInitTimer = TimerInit()
    Local $NewArrayPos = $FApos + $ArrayPos
    Local $GoToRow

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

    If (Not IsArray($FoundedArray)) Or $FoundedArray[0] == 0 Then
    SetStatus("Kein Sucherergebnis vorhanden")
    Return
    EndIf

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

    ; letztes Element überschritten?
    If $NewArrayPos > $FoundedArray[0] Then $NewArrayPos = 1

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

    ; erstes Element unterschritten
    If $NewArrayPos < 1 Then $NewArrayPos = $FoundedArray[0]

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

    ; Reihe nochmal setzen und hinspringen
    $GoToRow = $FoundedArray[$NewArrayPos]
    _GUICtrlListView_SetItemSelected($GuiListView, $GoToRow, True, True) ; Nur den einen setzen
    _GUICtrlListView_EnsureVisible($GuiListView, $GoToRow) ; Hinscrollen/Anzeigen

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

    ; Pointer umsetzen
    $FApos = $NewArrayPos

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

    SetStatus($NewArrayPos & " # " & $FoundedArray[0] & " gefundenen Items")

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

    _Debug("JumpToFoundedItem", 'jump to result ' & $NewArrayPos & " in row " & $GoToRow, ru_TimerDiffNice($MyLocalInitTimer))
    EndFunc ;==>JumpToFoundedItem

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

    ; Funktion, die den Text um unteren Rand der Gui ausgibt und ggf. den WaitingCursor setzt
    Func SetStatus($Text, $WaitingCursor = 0)
    ; Status ausgeben
    GUICtrlSetData($GuiStatusLabel, $Text)

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

    ; Cursor umsetzen
    If $WaitingCursor Then
    GUISetCursor(15, 1, $MyGui) ; Waiting-Cursor
    Else
    GUISetCursor(-1, 0, $MyGui) ; Normal-Cursor
    EndIf
    EndFunc ;==>SetStatus

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

    ; Funktion, die Debug-Ausgaben macht
    Func _Debug($VonFunc = "", $Text = "", $a = "", $b = "", $c = "", $d = "", $e = "", $f = "")
    Local $Message = '>' & $VonFunc & '<: ' & $Text

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

    If $a <> "" Then $Message &= ", " & $a
    If $b <> "" Then $Message &= ", " & $b
    If $c <> "" Then $Message &= ", " & $c
    If $d <> "" Then $Message &= ", " & $d
    If $e <> "" Then $Message &= ", " & $e
    If $f <> "" Then $Message &= ", " & $f

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

    ConsoleWrite($Message & @CRLF)
    EndFunc ;==>_Debug

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

    ; Funktion, die einen TimerDiff "schöne" Zeitangaben umwandelt und zurückliefert
    ; $typ == "I", dann muß in $InitOrDiffZahl das Ergebnis von TimerInit stehen
    ; $typ == "D", dann muß in $InitOrDiffZahl das Ergebnis von TimerDiff stehen, also das ausgerechnete TimeDifferenz
    Func ru_TimerDiffNice($InitOrDiffZahl, $typ = "I")
    Local $hh, $mm, $ss, $ret
    Local $TimerDiffZahl

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

    If $InitOrDiffZahl <= 0 Then Return ""

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

    ; Schauen, was übergeben wurde
    If $typ == "I" Then
    ; Ist InitTimer-Zahl, daher Diff berechnen
    $TimerDiffZahl = TimerDiff($InitOrDiffZahl)
    ElseIf $typ == "D" Then
    ; TimerDiff-Zahl direkt übernehmen
    $TimerDiffZahl = $InitOrDiffZahl
    Else
    ; Falscher Typ, einfach nichts zurückgeben
    Return ""
    EndIf

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

    ; Integer daraus machen
    $TimerDiffZahl = Int($TimerDiffZahl)

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

    ; hh, mm, ss füllen
    _TicksToTime($TimerDiffZahl, $hh, $mm, $ss)

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

    If $hh > 0 Then $ret &= StringFormat("%02ih ", $hh)
    If $mm > 0 Then $ret &= StringFormat("%02im ", $mm)
    If $ss > 0 Then $ret &= StringFormat("%02is ", $ss)
    If $ss < 1 Then
    $ret &= $TimerDiffZahl & " ticks"
    Else
    $ret &= "(" & $TimerDiffZahl & " ticks)"
    EndIf

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

    Return $ret
    EndFunc ;==>ru_TimerDiffNice
    #EndRegion Funktionsdefinitionen

    [/autoit]


    Probiert hatte ich auch schon von BugFix das "ListView - SubItem einzeln färben/formatieren ", aber das ist bei großen Tabellen leider zu langsam.

    Besten Dank schon mal für jede Idee!
    R@iner

  • Hallo Mega,

    in meinem eigentlichen (Haupt-)programm habe ich dazu leider keinen Platz. :(

    In meinen Augen gibt es nur 3 Möglichkeiten:
    - Ich blende in der aktuellen Liste die nicht benötigten Zeilen aus (wie ginge das?)
    - Ich markiere die Trefferzeilen deutlicher (nur wie?)
    - Ich tausche die alte Liste gegen die Trefferliste aus (wie ginge das am einfachsten?)

    Gruß
    R@iner

    • Offizieller Beitrag

    Hallo R@iner,

    die Frage ist, wie viele Treffer werden es? Muss der User immer alle Treffer sehen? Kann man die Visualisierung der Treffer irgendwo anders machen (statusbar)?

    In meinen Augen gibt es nur 3 Möglichkeiten:
    - Ich blende in der aktuellen Liste die nicht benötigten Zeilen aus (wie ginge das?)
    = da wäre sich das GuiCtrlSetState und dann hide und die Trefferliste neu aufbauen und an derselben Stelle anzeigen am schnellsten.
    - Ich markiere die Trefferzeilen deutlicher (nur wie?)
    = Hintergrundfarbe (ist aber wahrscheinlich zeitintensiv)
    - Ich tausche die alte Liste gegen die Trefferliste aus (wie ginge das am einfachsten?)
    Siehe Antwort a :)

    Mega

  • Wie wärs mit überzeichnen vom alten Listview und das neue mit den Treffern füllen?
    Mit GUICtrlSetState kannst du die controls anzeigen und verstecken.

    edit \ zu langsam :whistling: Die Variante ist aber wohl am besten.

  • Hallo Mega, hallo Nuts,

    die Frage ist, wie viele Treffer werden es?


    schwer zu beantworten. Vermutlich kann es eine große Liste werden. Zwischen einem und viele Treffer.

    Es handelt sich um die Firmwareliste. Die zentral gepflegte Liste enthält derzeit ~80 Einträge und wenn der User noch lokal gespeicherte Firmwaren hat, dann kommen die auch noch dazu. Bei einigen Sammlern sind das bis zu 200 Einträge dazu.

    (Veraltete) Screenshots vom eigentlichen Programm, Bilder 2-4: Klick mich

    Der Wunsch der User ist es eben, dass in dieser Firmwareliste gesucht werden kann. Ich suche halt jetzt nach einer einfachen aber guten Lösung zum Suchen/Filtern.

    Ich weiß, die Gui ist nicht der Bringer, aber ich steh damit auf Kriegsfuß.

    Zitat von Xenobiologist

    Muss der User immer alle Treffer sehen?


    Wenn ich eine neue Liste mache, dann ja.

    Zitat von Xenobiologist

    Kann man die Visualisierung der Treffer irgendwo anders machen (statusbar)?


    Ne

    Zitat von Xenobiologist


    = da wäre sich das GuiCtrlSetState und dann hide und die Trefferliste neu aufbauen und an derselben Stelle anzeigen am schnellsten.


    Ah ok, muss ich mir anschauen. Kann ich die "Hauptliste" kopieren und die unnötigen Rows rauslöschen oder was geht Eurer Meinung nach am schnellsten?

    Zitat von Xenobiologist


    = Hintergrundfarbe (ist aber wahrscheinlich zeitintensiv)


    Das habe ich schon letztes Jahr probiert um die unterschiedlichen Firmwaretypen deutlicher zu kennzeichnen, aber das war viel zu langsam.

    Besten Dank!
    R@iner

    • Offizieller Beitrag

    Hi,

    andersrum ist denke ich schneller.
    Beide Listviews erstellen gleiche Koordinaten
    AlleAnzeigenLV und TrefferLV

    AlleAnzeigenLV show
    TrefferLV hide
    nach dem Suchen die TrefferLV im Hintergrund füllen und anschließend die Sichtbarkeit switchen.

    Was du noch machen könntest, wäre ein _IECreateEmbedded in die GUI übernehmen und einfach die Suchliste als html anzeigen. Dann kannst du sie Suche des IE nutzen bzw sämtliche Darstellungsmöglichkeiten von HTML etc. nutzen. (und das sehr sehr schnell!)

    Mega

  • Hallo Mega,

    ich muss mal schauen, ob ich das hin bekomme. Da ich unten Buttons habe und auch nen eigenen ListView-Handler geschrieben habe, die von der Haupt-ListView Daten auslesen, bearbeiten und auch zurückschreiben, muss ich mir das nochmal gründlich überlegen, ob ich eine zweite Liste einführe, nicht dass ich mehr kaputt mache.

    Und daher funktioniert auch das mit dem _IECreateEmbedded nicht, da die Buttons darauf ja reagieren sollen und auch die Liste verändern.

    Dann bleibe ich wohl bei meinem ersten Wurf, wobei mir der nicht gefällt, aber damit muß ich nicht zuviel ändern.

    Hast Du noch ne Idee, wie ich die einzelnen Zeilen deutlicher markieren könnte, also außer der Hintergrundfarbe?

    Gruß
    R@iner

  • Hello again,

    ich gestell mich gerade recht blöd mit _GUICtrlListView_SetItemImage. :(

    Da könnte ich am Anfang der Reihe evtl nen Pfeil setzen. Aber wie lösche ich den wieder?

    Ich muss wohl zuerst ne Image-Liste mit _GUIImageList_Create erzeugen. Da würde ich gerne den Pfeil hinzufügen.
    Vermutlich mit _GUIImageList_AddIcon($hImage, @SystemDir & "\shell32.dll", 137)

    Nur sobald ich die Liste erzeuge, haben automatisch alle Reihen den Pfeil, auch ohne dass ich den explizit den Reihen gesetzt habe :(

    /edit:
    Problem mit der Image-Liste gelöst. In der Liste habe ich nun 2 Elemente. Element 1 ist ein weisses Feld und das zweite Element ist der Pfeil.

    Gruß
    R@iner

    Einmal editiert, zuletzt von skyteddy (17. Juni 2010 um 20:13)

  • Hallo nochmal,

    ich hab mich jetzt nochmal mit der ListView und den Suchmöglichkeiten nach Items beschäftigt.

    Erstmal habe ich getestet, welche der 3 Methoden am schnellsten ist, um ein ListView zu "befüllen".
    1) mit _GUICtrlListView_AddItem und _GUICtrlListView_AddSubItem => 03s (3337 ticks)
    2) mit GUICtrlCreateListViewItem => 04s (4061 ticks)
    3) Array erzeugen und mit _GUICtrlListView_AddArray => 655 ticks

    Ergebnis: Mit Abstand ist die Methode 3 via Array-Erzeugung und _GUICtrlListView_AddArray am schnellsten.

    Motiviert durch das gute Ergebnis dachte ich mir, dass ich gewiss auch noch Geschwindigkeit beim Suchen in der ListView respektive des Arrays herausholen kann.
    Und da begannen meine Probleme. :(

    Suchmethode A mit _GUICtrlListView_FindInText:
    => Das liefert mir ein Array mit Rows zurück, die ich dann in meiner Funktion zum Vor- und Zurückblättern der gefundenen Reihen einfach durchgehe. Dies funktioniert

    Gut dachte ich mir, das Suchen in Arrays wird gewiss schneller sein und ich habe mich damit versucht:

    Suchmethode B mit _ArrayFindAll:
    => Hier bin ich zu doof um die Reihen zu ermitteln. Mir scheint es so, als sucht der nicht in 2D. Wie muss ich das machen, dass mir alle Reihen geliefert werden?

    Da das nicht funktionierte, probierte ich mein Glück mit _ArraySearch

    Suchmethode C mit _ArraySearch:
    => Liefert mir irgendwas, aber nicht das, was ich brauche. Vermutlich muss ich "per Hand" alle Dimensionen durchgehen um die Reihen zu ermitteln, oder wie geht das?

    Gefrustet von dem Ergebnis, habe ich dann auf _Array2DSearch zurückgegriffen

    Suchmethode D mit _Array2DSearch:
    => Liefert mir zwar zuviel Ergebnisse, also Reihe und Spalte, aber daraus kann ich die Reihen rausfiltern.
    Nur jetzt habe ich ein neues Problem. Das Array mit den gefundenen Rows stimmt, aber wenn ich diese Methode verwende funktioniert mein Umblättern in der Funktion "JumpToFoundedItem()" nicht mehr, obwohl das Array absolut identisch ist mit dem aus der Suchmethode A. Es scheint so, als würde _GUICtrlListView_SetItemSelected und _GUICtrlListView_EnsureVisible nicht mehr funktionieren :(

    Ich finde einfach die Fehler nicht. :-((

    In Zeile 231 - 235 kann man die Suchmethode einstellen. Entweder 1 oder mehrere. Das Ergebnis der letzten Methode wird halt genommen.

    Kurzzusammenfassung:
    - Wenn ich nur Methode 1 nehme, funktioniert es
    - Wenn ich nur Methode 4 nehme, die eigentlich das gleiche Ergebnis liefert wie Methode 1, funktioniert das Vor- und zurückblättern nicht. Warum?
    - Methode 2 und 3 liefern schon gleich unbrauchbare Reihenangaben. Wie muss ich das richtig machen?

    Ich hoffe der Code ist lesbar.

    Besten Dank im voraus und ein schönes Wochenende!
    R@iner

  • Hallo Zusammen,

    ich hab es gelöst, wobei mir nicht ganz klar ist, warum man bei _ArrayFindAll und _ArraySearch selber in einer Schleife alle SubItems durchgehen muss. Ich dachte, das wäre gerade der Vorteil von _ArrayFindAll.

    Entweder hab ich ursprünglich den falschen Parameter benutzt um es in einem Rutsch zu machen, oder es geht einfach nicht, in einem 2D-Array alle Reihen auf einmal rauszusuchen.

    Den Fehler warum _GUICtrlListView_SetItemSelected/_GUICtrlListView_EnsureVisible nicht funktioniert, obwohl das Array definitiv die richtigen Werte enthält, ist mir bis jetzt auch noch nicht klar.

    Als Workaround habe ich ein in meinen Augen überflüssiges _GUICtrlListView_ClickItem eingebaut, aber jetzt geht es wenigstens.

    Anbei der letzte Wurf der funktioniert, wobei die Fragen dennoch offen bleiben.

    Schönen Sonntag!
    R@iner

    /edit:
    Gibt es auch eine Alternative für den reihenweisen Farbwechsel, also die Alternative zu
    GUICtrlSetBkColor($GuiListView, $ColorLVungerade) ; Farbe ungerade Zeilen
    GUICtrlSetBkColor($GuiListView, $GUI_BKCOLOR_LV_ALTERNATE)
    wenn man das ListView mit _GUICtrlListView_AddArray befüllt?

  • Hallo Paule,

    uiii, cool, merci! Ganz anderer Ansatz. :) Sieht auf den ersten Blick kompliziert aus, ist aber wahrscheinlich um vieles einfacher.

    Das muss ich mir mal in Ruhe zu Gemüte führen.

    Danke nochmal und nen schönen Sonntag!
    R@iner

    • Offizieller Beitrag

    Gibt es auch eine Alternative für den reihenweisen Farbwechsel, also die Alternative zu
    GUICtrlSetBkColor($GuiListView, $ColorLVungerade) ; Farbe ungerade Zeilen
    GUICtrlSetBkColor($GuiListView, $GUI_BKCOLOR_LV_ALTERNATE)
    wenn man das ListView mit _GUICtrlListView_AddArray befüllt?


    Klar, kein Problem mit WM_NOTIFY:

    Spoiler anzeigen
    [autoit]

    $gui = GUICreate('Test 2')
    $ListView1 = GUICtrlCreateListView("Col 1|Col 2", 15, 15, 300, 250)
    $hLV = GUICtrlGetHandle(-1)
    _GUICtrlListView_SetColumnWidth($hLV, 0, 148)
    _GUICtrlListView_SetColumnWidth($hLV, 1, 148)

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

    Local $aToFill[30][2]
    For $i = 0 To 29
    $aToFill[$i][0] = Random(10000, 1000000, 1)
    $aToFill[$i][1] = Random(10000, 1000000, 1)
    Next
    _GUICtrlListView_AddArray($hLV, $aToFill)

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

    GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
    GUISetState()

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

    Do
    Until GUIGetMsg() = -3
    GUIDelete($gui)

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

    Func WM_NOTIFY($hWnd, $Msg, $wParam, $lParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    If $hWndFrom = $hLV Then
    Switch $iCode
    Case $NM_CUSTOMDRAW
    Local $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
    Local $iDrawStage, $iItem, $iSubitem, $hDC, $tRect
    $iDrawStage = DllStructGetData($tCustDraw, 'dwDrawStage')
    Switch $iDrawStage
    Case $CDDS_ITEMPREPAINT
    Return $CDRF_NOTIFYSUBITEMDRAW
    Case BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM)
    $iItem = DllStructGetData($tCustDraw, 'dwItemSpec')
    Switch Mod($iItem, 2)
    Case 0 ; geradzahlig
    DllStructSetData($tCustDraw, 'clrTextBk', 0x23FFFF)
    Case 1 ; ungeradzahlig
    DllStructSetData($tCustDraw, 'clrTextBk', 0x0044FF)
    EndSwitch
    Return $CDRF_NEWFONT
    EndSwitch
    EndSwitch
    EndIf
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

    [/autoit]
  • Hallo BugFix,

    dank Dir für das Beispiel. Es scheint so, als wäre es zusammen kopiert, denn es ist nicht lauffähig. Oder fehlen da neben Windowsconstants.au3 noch andere Includes?

    Kannst Du bitte die offenen Fragen noch zum _ArrayFindAll beantworten bzw. gleich Dein Tutorial umd die 2D-Suche erweitern.
    Ist das so, dass man bei _ArrayFindAll alle SubItems einzeln durchsuchen muss? Und was ist der Vorteil gegenüber _ArraySearch ?

    Besten Dank und nen schönen Sonntag!
    R@iner

    • Offizieller Beitrag

    ^^
    Ich hab es aus einem größeren Skript auf das Wesentliche reduziert.
    Aber die Includes fehlten noch:
    #include <GUIConstantsEx.au3>
    #include <GuiListView.au3>
    #include <StructureConstants.au3>
    #include <WindowsConstants.au3>

    Damit läuft es.
    Wegen der anderen Sachen schau ich mal.

    Edit:
    Also zu den anderen Dingen:
    _ArrayFindAll() ist nur begrenzt brauchbar, da im Gegensatz zu dem, was der Funktionsname erwarten läßt, nur die Vorkommen in einer Spalte gefunden werden. Das ist auch der einzige Unterschied zu _ArraySearch(), welches nur das erste Vorkommen in einer Spalte findet.

    Um wirklich ALLE Vorkommen zu finden kannst du so vorgehen:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

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

    Local $a[4][2] = [[11,22],[12,22],[22,13],[11,15]]

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

    ; _ArrayFindAll arbeitet nur innerhalb einer Spalte!
    ; Um wirklich ALLE Vorkommen zu finden, muß es auf jede Spalte angewendet werden
    $search = 22
    $sFound = ''
    For $i = 0 To UBound($a, 2) -1
    $found = _ArrayFindAll($a, $search,0,0,0,0,$i)
    For $j = 0 To UBound($found) -1
    $sFound &= $found[$j] & ',' & $i & '|'
    Next
    Next
    $sFound = StringTrimRight($sFound, 1)

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

    $aFound = StringSplit($sFound, '|', 2)

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

    Local $aFoundIndexes[UBound($aFound)][2]
    For $i = 0 To UBound($aFound) -1
    $var = StringSplit($aFound[$i], ',', 2)
    $aFoundIndexes[$i][0] = $var[0]
    $aFoundIndexes[$i][1] = $var[1]
    Next
    _ArraySort($aFoundIndexes)
    _ArrayDisplay($aFoundIndexes) ; Fundstelle als: [0]=Item/ [1]=SubItem

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

    ; === Unterschied beider Funktionen
    ; _ArraySearch findet das ERSTE Vorkommen des Suchbegriffs in EINER Spalte
    ; _ArrayFindAll findet ALLE Vorkommen des Suchbegriffs in EINER Spalte

    [/autoit]
  • Hallo BugFix,

    danke für die Bestätigung wegen der Array-Fragen! Dann hab ich ja in Posting 12 ja alles richtig gemacht :)

    Die AutoIt-Doku dazu ist unzureichend bzw. irreführend. Ich bleib daher besser bei deinem _Array2DSearch und werde es mir so modifizieren, dass nur die Items und nicht auch noch die SubItems geliefert werden. Dann hab ich alles, was ich brauche.

    Danke auch für die Lösung mit dem WM_NOTIFY. Eine Frage dazu habe ich noch:
    Da ich den Inhalt des ListViews immer wieder verändere, sollte auch das Redraw gestoppt werden, während ich z.B. die Spaltenbreite einstelle.
    Normalerweise gibt es dazu ja _GUICtrlListView_BeginUpdate und _GUICtrlListView_EndUpdate, aber das scheint den WM_NOTIFY nicht wirklich zu interessieren, oder gibt es da auch was dazu?

    Hier dein modifizierter Code, damit sehe ich es zumindest auf meinem alten Rechner deutlich.

    Happy computing!
    R@iner

  • Hallo Pinguin94,

    sorry, aber ich verstehe Deine frage nicht. Was meinst Du mit Header fixieren?

    Mein Hauptproblem habe ich in Posting 1 und 6 beschrieben. Ich will in einem ListView filtern und entweder die gefilterte Liste darstellen oder in der Originalliste vor und zurückspringen zu den gefundenen Einträgen. Und das Füllen der ListView geht ja mit _GUICtrlListView_AddArray am schnellsten, allerdings würde ich gerne jede zweite Reihe einfärben, damit die Liste leichter lesbar ist.

    Der wm_notify von BugFix hilft, aber ist nicht so besonders schnell, zumal er anscheinend den Redraw im Fenster sofort macht. Und die Aktualisierung des ListViews kann man normalerweise _GUICtrlListView_BeginUpdate und _GUICtrlListView_EndUpdate unterbinden. Das klappt aber irgendwie nicht, wenn der wm_notify verwendet wird.

    Ich hoffe, es ist jetzt klarer.

    Happy computing!
    R@iner