ListView füllen und ProgressBar

  • Ich ärgere mich schon länger darüber, wie lange es dauert, eine ListView zu befüllen.

    Trotz Verwendung von _GUICtrlListView_BeginUpdate($idListView) und seinem Gegenstück, dauert es bei 1600 Datensätzen zu je 32 Feldern fast 10 Sekunden, bis man das Ergebnis in der Listview sieht.

    Auf der Suche nach dem Zeitfresser staunte ich nicht schlecht, denn ich konnte den Verursacher nicht dingfest machen, wohl aber die Stelle, wo es klemmt.

    Die folgende Routine ist zwar isoliert nicht lauffähig (bei Bedarf poste ich das ganze Programm, samt Datenbank), aber ich glaube man versteht bestens, was hier los ist:

    P.S.: In der Codeauswahl des Forums ist "AutoIt" plötzlich nicht mehr verfügbar ...

    Ich code, also bin ich!

  • Wie lange dauert es denn die Datenbank zu queryen?

    Du setzt deine ProgressBar mit $i aber wie hoch zählt denn dein i? ProgressBars akzeptieren Werte von 0 bis 100,

    es ist keine gute Idee jedes Mal die ProgressBar zu setzen, da deine GUI den Teil (ich denke aber nicht die gesamte GUI) neu zeichnen muss.

    Also aktualisiere deine ProgressBar wenn sich an einem ganzen Prozent was geändert hat 0.05 = 0.10 = 0.9% != 1% (du verstehst was ich meine).

    Zum Test kannst du ja mal deine Progressbar weglassen und wirklich nur deine ListView füllen.

  • Hallo alpines,

    nein, das mit der Progressbar und der Schleife ist nicht der Punkt.

    Die Schleife selbst wird ja ratzfatz durchlaufen und zugleich die PrograssBar bis zum Anschlag gefüllt.

    Das geht aus den beiden Zeilen unter der Schleife hervor, denke ich.

    ... ABER - ich habe das Problem eben gerade selbst entdeckt (schäm!) - die Progressbar erwartet Werte im Bereich bis maximal 100, ist also auf Prozent gebürstet.

    Das war in der Programmiersprache, in der ich zuletzt unterwegs war, anders.

    GANZ DOLL SCHÄM!

    OK, die Schleife wird bei 1600 Datensätzen also doch nicht so ruckzuck durchlaufen, wie meine Progressbar den irrigen Anschein erweckte, die ja schon bei 100 am Anschlag war, ergo lange vor den 1600 Schleifen-Durchläufen ... <:-(

    Bin nun schlauer, danke für die Antwort!

    Jetzt muss ich mich gezielt darum kümmern, die Schleife zu beschleunigen.

    Die Progressbar hatte ich übrigens erst heute eingebaut. Auch ohne die benötigt die Routine ihre knapp 10 Sekunden.

    Die Zeile mit GUICtrlSetData in der Schleife verlangsamt diese übrigens nicht wahrnehmbar.

    (Ist natürlich trotzdem unelegant, die Progressbar bei jedem $i zu aktualisieren, ganz davon abgesehen, dass es - wie nun geklärt - in dieser Form keinen Sinn macht.)

    Btw.: IMHO dürfte die Hilfedatei (für Dussels wie mich) gerne explizit darauf hinweisen, dass bei 100 Schluss ist ...

    Ich code, also bin ich!

  • Hallo Code-Jack

    Es korrespondiert nicht so gut mit deinem aktuellen Ansatz mit der Progressbar. Allerdings kann ich mir vorstellen, dass das Füllen der Listview deutlich schneller ginge, wenn sie nicht in der Schleife füllen würdest. Du könntest ein Array füllen und dann statt: GUICtrlCreateListViewItem(_ArrayToString($aDatentaxi, '|', 1, 21), $idListView) einmal _GUICtrlListView_AddArray benutzen.

    Grüße autoiter

  • Du könntest ein Array füllen und dann statt: GUICtrlCreateListViewItem(_ArrayToString($aDatentaxi, '|', 1, 21), $idListView) einmal _GUICtrlListView_AddArray benutzen.

    Dann möchte ich schon mal vorweg sagen, bitte nicht in jedem Schritt ReDim verwenden sondern direkt die passende Größe erstellen.

    Wenn du kannst (Ich hab mir AddArray nicht angeschaut) kannst du direkt so queryen, dass es formatpassend ist und direkt übergeben.

  • Nimm anstelle von _SQLite_Query _SQLite_GetTable2d.

    • Wenn dann noch das SQL Statement analog zur LV aufebaut ist kannst du auch noch anstelle von GUICtrlCreateListViewItem(um eine LV-Zeile zu erstellen) _GUICtrlListView_AddArray verwenden und das komplette Egebnis auf eimal einzutragen.
      Schnellste Methode
    • Falls es aber das Egebnis nicht zulässt, musst du in einer Schleife durch das erhaltene Array (Ergebbnis von _SQLite_GetTable2d) gehen und GUICtrlCreateListViewItem verwenden.
      Selbst diese Methode ist noch deutlich schneller als dein Ansatz mit _SQLite_Query.

    Die LV-Farben kannst du auch auf einmal setzen:

    Code
        ; Set colors
        _GUICtrlListView_SetBkColor($idListview, $CLR_MONEYGREEN)
        _GUICtrlListView_SetTextColor($idListview, $CLR_BLACK)
        _GUICtrlListView_SetTextBkColor($idListview, $CLR_MONEYGREEN)

    dies sollte auch noch einmal (minimal) Zeit sparen.

  • Sehr gute Tipps, danke!

    Ich habe mal autoberts Vorschlag umgesetzt: Statt einer Schleife verwende ich nun _SQLite_GetTable2d.

    Das hat die Sache wirklich deutlich beschleunigt, große Klasse! :thumbup:

    Was mir aber partout nicht gelingen will, ist das alternierende Einfärben der ListView-Einträge.

    Kreieren tue ich die ListView am Programmbeginn so:

    C
    $idListView = GUICtrlCreateListView($sListViewHeader, 10, 40, 1150, 260, $LVS_SHOWSELALWAYS, BitOr($LVS_EX_FULLROWSELECT, $LVS_EX_HEADERDRAGDROP))  ;# Spaltenköpfe per Maus umsortierbar!
    GUICtrlSetBkColor(-1, 0xFFFFFF) ; Color weiß
    GUICtrlSetBkColor(-1, $GUI_BKCOLOR_LV_ALTERNATE)
    GUICtrlSetFont(-1, 10, 400, 0, "Arial")

    Und meine jüngst umgebaute Routine zum Befüllen der ListView sieht jetzt so aus:

    (Habe es in der Codebox notgedrungen als "C-Code" markiert, weil man im Forum"AutoIt" nicht mehr zur Auswahl hat.)

    Das Resultat ist jedenfalls eine ruckzuck und ordnungsgemäß prall gefüllte ListView, aber leider mit schneeweißem Hintergrund.

    - Nix mit alternierend gefärbten Einträgen. :'-(

    Alle meine Versuche, das zu ändern, scheiterten kläglich (und wie so oft, hilft die Hilfedatei nicht wirklich).

    Ich code, also bin ich!

  • GUICtrlSetBkColor(-1, 0xFFFFFF) ; Color weiß
    GUICtrlSetBkColor(-1, $GUI_BKCOLOR_LV_ALTERNATE)

    Hihi... nein, also so nicht, denn mit dem zweiten Befehl überschreibst du ja den ersten.

    Quatsch... wird nicht überschrieben, weil $GUI_BKCOLOR_LV_ALTERNATE ein Special Flag ist... finde es aber irgendwie schräg, dass es mit GUICtrlSetBkColor() gesetzt wird... und kein Aas korrigiert mich, wenn ich Müll labere... 8o Für meine Begriffe hätte man sich dieses stiefmütterliche "Feature" sparen können... ich will die Farbe für jedes Item bzw. jede Zelle explizit bestimmen können.

    From the help file

    The special flag $GUI_BKCOLOR_LV_ALTERNATE can be used with Listview control to give alternate background of the ListviewItems lines.

    The odd lines will get the color set by GUICtrlSetBkColor of the Listview control.

    The even lines will get the color set by GUICtrlSetBkColor of the ListviewItem control.

    Das Problem dabei ist, dass du dann nicht mehr _GUICtrlListView_AddArray verwenden kannst... aber hier findest du eine alternative Möglichkeit. Den Link zum Download findest du am Ende des ersten Beitrags.

    Schau dir vielleicht zuerst das Beispiel \ListViewColorsFonts\Examples\3) Alternating colors\1) Alternating row colors.au3 an...

    Einmal editiert, zuletzt von Bitnugger (20. November 2018 um 15:00)

  • Wenn alle Stricke reißen, dann muss ich wohl den von Dir verlinkten Weg gehen, Bitnugger.

    Zuvor habe ich es aber mal "klassisch" probiert, jeden zweiten Eintrag der bereits gefüllten ListView in einer Schleife umzufärben, jedoch ohne Erfolg:

    C
    Local $idLVI
    ;GUICtrlSetBkColor($idListView, $GUI_BKCOLOR_LV_ALTERNATE)
    GUICtrlSetBkColor($idListView, 0xA0E68C)
    
    For $i = 1 to 20 Step 2 ;$iTreffer Step 2
       $idLVI = _GUICtrlListView_MapIndexToID($idListView, $i)
       ConsoleWrite("$i = " & $i & "  $idLVO = " & $idLVI & @CRLF)
       GUICtrlSetBkColor($idLVI, 0xF0E68C) ;# (0xF9F9F9) helles Grau (0xB9D1EA) helles blau (0xF0E68C)
       ;_GUICtrlListView_SetTextBkColor($idLVI, 0xB9D1EA)
    Next

    Mich wundert, dass ...MapIndexToID laut Hilfe angeblich eine echte, beständige ID zurück liefern soll.

    In der Konsole erscheint bei mir:

    $i = 1 $idLVO = 1

    $i = 3 $idLVO = 3

    $i = 5 $idLVO = 5

    $i = 7 $idLVO = 7

    $i = 9 $idLVO = 9

    $i = 11 $idLVO = 11

    $i = 13 $idLVO = 13

    $i = 15 $idLVO = 15

    $i = 17 $idLVO = 17

    $i = 19 $idLVO = 19

    Ich hätte eher eine Art Handle erwartet, als Rückgabewert.

    GUICtrlSetBkColor scheint mit dieser Art von ID jedenfalls ebenfalls unzufrieden zu sein.

    Ich code, also bin ich!

  • Mich wundert, dass ...MapIndexToID laut Hilfe angeblich eine echte, beständige ID zurück liefern soll.

    In der Konsole erscheint bei mir:

    GUICtrlSetBkColor scheint mit dieser Art von ID jedenfalls ebenfalls unzufrieden zu sein.

    Ich vermute mal, GUICtrlSetBkColor funktioniert wohl nur, wenn das Item mit GUICtrlCreateListViewItem erstellt wurde.

  • Ich vermute mal, GUICtrlSetBkColor funktioniert wohl nur, wenn das Item mit GUICtrlCreateListViewItem erstellt wurde.

    Korrekt, daher folgender Lösungsvorschlag (C + P quer durch die Hilfe):

  • Da ich derzeit keine Beiträge bearbeiten kann, hier eine neue Version:

    Einmal editiert, zuletzt von autoBert (20. November 2018 um 16:08)

  • Jupp, diesen Ansatz hatte ich schon aus Deinem Posting Nr. 7 herausgelesen, autobert.

    Dein Beispiel funzt und ist auch bei Erweiterung auf 1000 Datensätze angenehm flott.

    Heute Abend baue ich das mal real in mein Programm ein. Mal schauen, ob es dann immer noch flott ist (ich habe mehr Felder pro Datensatz).

    Vermutlich macht es Sinn, zudem noch alpines' Tipp aufzugreifen und das Array zuvor passend zu kreieren. Denn möglicherweise verursacht _SQLite_GetTable2d() massenhaft ReDims (muss ich testen, ob dem so ist).

    -------------

    Übrigens ist das mal wieder so ein Punkt, wo die Hilfefunktion gerne etwas ausgebaut werden könnte.

    Wenn das Umfärben von ListView-Einträgen nur bei einzeln kreierten Einträgen klappt, jedoch kläglich versagt, wenn man zuvor ein ganzes Array übergeben hat, dann müsste diese wichtige Info in die Hilfe!

    Die sinnlose Probiererei hat mich Stunden gekostet, inklusive der Forenpostings. Euch hilfreiche Geister hat es ebenfalls Zeit gekostet (vielen Dank dafür!).

    Und noch immer, trotz allem RTFM und allerhand Probiererei, blicke ich nicht völlig klar, in welchen Fällen $GUI_BKCOLOR_LV_ALTERNATE das tut, was man erwartet, oder es eben nicht tut.

    Schade, dass die Hilfe dieses spezielle Flag bei GUICtrlCreateListView und bei GUICtrlCreateListViewItem zwar im Text erwähnt, dessen konkreten Einsatz dort aber im Beispielcode nicht demonstriert.

    Immerhin: Bei GUICtrlSetBkColor wird der Einsatz auch im Quelltext gezeigt, dort wird aber gleich wieder verwirrt/relativiert mit den mehrfach vorhandenen Zeilen:

    ; The following line could be dropped as the background color is taken from the listview.

    - Sicher versteht man das irgendwann, wenn man lange genug herumgetüftelt und sich mehrmals quer durch die Hilfe geackert hat. Aber ich habe den Eindruck, dass selbst Ihr erfahrenen Power-User nicht gerade auf Anhieb durchgeblickt habt, oder?

    Für einen Einsteiger finde ich die Hürde schon ziemlich hoch!

    Der Text macht Hoffnung, dass $GUI_BKCOLOR_LV_ALTERNATE der Bringer wäre, doch man probiert und probiert, es geht jedoch partout nicht.

    Ich code, also bin ich!

  • Dein Beispiel funzt und ist auch bei Erweiterung auf 1000 Datensätze angenehm flott.

    Das Beispiel nutzt eine Memory DB, bei Datenbank Datei wird es sich deutlich verlangsamen.

    Vermutlich macht es Sinn, zudem noch alpines' Tipp aufzugreifen und das Array zuvor passend zu kreieren. Denn möglicherweise verursacht _SQLite_GetTable2d() massenhaft ReDims (muss ich testen, ob dem so ist).

    _SQLite_GetTable2d() wird eine Variable für das Array ByRef übergeben, das Array wird anhand der Rückgabe des ausgeführten SQL-Queries 1mal dimensioniert und in einer Schleife befüllt. Also kein einziges ReDim!

    Einmal editiert, zuletzt von autoBert (20. November 2018 um 15:45)

  • Ich habe es jetzt also mal real ausprobiert.

    Und das Ergebnis ist übel!

    Dieser Code (basierend auf den Vorschlägen von autobert), ist krötig lahm:

    Obiger Code ist doppelt so langsam wie mein ursprünglicher Code.

    Hier ist er noch einmal:

    Trotz der Fortschrittsanzeige, läuft mein alter Code also doppelt so schnell.

    Drei Meldungen gebe ich jeweils in der Console aus, um zu sehen, wo die Zeit verschwendet wird.

    Entgegen autoberts erstem Satz in Posting 7, ist mein ursprüngliches _SQLite_Query und _SQLite_FetchData bedeutend schneller, als _SQLite_GetTable2d.

    In meinem alten Code kommen die Meldungen "Eins" und "Zwei" unmittelbar nacheinander.

    Nicht so bei autoberts _SQLite_GetTable2d. Da dauert es so ca. 3 Sekunden.

    Der wahre Zeitfresser sitzt aber bei beiden Codes zwischen den Konsolemeldungen "Zwei" und "Drei". Also in der Schleife.

    Der Code nach autoberts Vorschlag verheizt hier klägliche 25 Sekunden.

    Mein alter Code dagegen nur 12 Sekunden, trotz der Zusatz-Aufgabe mit der Progressbar.

    In beiden Fällen setze ich _ArrayToString ein. Der Unterschied ist aber, dass dieser Befehl bei meinem alten Code nur ein 1D-Array zu einem String zusammen datschen muss, wohingegen im auf autoberts Vorschlag basierten Code die Felder jeweils aus dem 2D-Array zusammengeklaubt werden müssen.

    Das ist aber nicht der Zeitfresser (was mich wundert). Ich habe dann nämlich mal eine Kombination beider Codes versucht:

    Zuerst fülle ich mein 1D-Array "Datentaxi" (mit nur einer Zeile), um dann im Code gemäß autoberts Vorschlag nur noch dieses 1D-Array behandeln zu müssen, bei jedem Schleifendurchlauf.

    Ist für Testzwecke ja egal, dass es stets die selbe Zeile ist.

    Und das Ergebnis ist so lahm, wie beim 2D-Array, was mich nun total wundert!

    Hier im Detail:

    Zwischen den Konsole-Meldungen Zwei und Drei liegen rund 30 Sekunden (nie exakt gemessen, einfach nach Gefühl gezählt).

    Mir unerklärlich, was im letzten Code der Zeitfresser ist, gegenüber meinem alten Code?


    Was wirklich flott ging, das war der Weg, das komplette 2D-Array direkt in die ListView zu schieben. Nur haperte es da an der alternierenden Einfärbung der Zeilen.

    Jetzt bleibt mir noch zu hoffen, dass Bitnuggers "alternative Möglichkeit" (am Ende von Posting Nr. 9) was reißt.

    Sehr optimistisch bin ich jetzt aber nicht mehr.

    Ich code, also bin ich!

    Einmal editiert, zuletzt von Code-Jack (20. November 2018 um 19:15)

  • Hallo Code-Jack

    Hier noch mal der beste Vorschlag des Threads aus meiner Sicht:

    Lade erst mal etwa das 3-fache des sichtbaren Bereiches (vermutlich etwa <200 Einträge) . Das lässt du anzeigen und beginnst anschließend mit dem Laden des Restes. Die Gesamtzeit bleibt natürlich gleich, aber optisch sieht es nach gut 1s schon geladen aus.

    Alternativ möchte ich möchte auch das Programm-Design hinterfragen. Ist es wirklich nötig immer 1600 und mehr Datensätze mit 32 Feldern in einer Listview darzustellen? Ich glaube nein. Das schaut man sich doch immer gefiltert mit einer bestimmten Sortierung an.
    Dazu würde ich schon vordefinierte Filter bereitstellen. Unter anderem einen für die maximale Menge der Trefferliste. Wenn der etwa auf hundert steht, geht das Leeren der Liste, das Abfragen und das neue Füllen doch sehr schnell.

    Grüße autoiter

  • Hier mal eine Demo...

    Code: Ausgabe
    ! Array $aLV[1600][32] erzeugen...         benoetigte Zeit: 0 Sekunden
    ! Breite/Ausrichtung der Items anpassen... benoetigte Zeit: 1 Sekunden
    ! Array im Listview anzeigen...            benoetigte Zeit: 8 Sekunden
    ! Farben im Listview setzen...             benoetigte Zeit: 2 Sekunden
  • Bitnugger, Du bist der König unter den Königen!

    Ich dachte, der Warp-Antrieb wäre noch gar nicht erfunden, doch ich irrte!

    Dieses ListViewColorsFonts.au3 läuft ganz definitiv mit Warp!

    Übrigens weiß ich nicht, wieso Du so schlechte Werte in der Konsole hast?

    Auf meinem alten Bürorechner mit OnBoard-Grafik (also wahrlich kein Rechenmosnter) bekomme ich mit Deinem Script folgende Ausgabe:

    Code
    ! Array $aLV[1600][32] erzeugen...         benoetigte Zeit: 0 Sekunden
    ! Breite/Ausrichtung der Items anpassen... benoetigte Zeit: 0 Sekunden
    ! Array im Listview anzeigen...            benoetigte Zeit: 1 Sekunden
    ! Farben im Listview setzen...             benoetigte Zeit: 1 Sekunden

    In hoffnungsvoller Erregung habe ich den Code dann mal in mein Programm eingefrickelt.

    - Ein Traum!!!

    Keine 5 Sekunden nach dem Drücken von F5 im Editor, steht die gesamte GUI da, mit gefüllter und gefärbter ListView!

    Davon verheize ich knapp eine Sekunde anderweitig und rund zwei Sekunden mit dem Füllen des 2D-Arrays aus der SQLite-Datenbank.

    Das eigentliche Füllen und Färben der ListView geschieht dann mit einem Extrakt aus Deinem Code, der seinen Job in nur rund zwei Sekunden erledigt.

    GROßARTIG!!! :thumbup: 

    (Schade, es gibt hier keinen Kotau-Smiley)

    Ich code, also bin ich!

  • Übrigens weiß ich nicht, wieso Du so schlechte Werte in der Konsole hast?

    Bin selbst auch sehr erstaunt... zumal ich auf einem AMD Turion(tm) II Neo N54L Dual-Core Processor (Windows 7 Home X64) fast dieselben Werte wie du habe, aber auf meinem Intel i7 920 Quad-Core Processor (Windows 10 Pro X64) so miserable Werte. Auf Windows 10 hatte bis gestern allerdings noch für openfiles das Scannen von lokalen Dateien mit der Option /Local ON aktiviert, was den PC merklich ausbremst. Das Deaktivieren dieser Option hat aber lediglich 1 Sekunde an Geschwindigkeitsgewinn gebracht.

    Kann bitte mal jemand testen, wie schnell es bei ihm auf einem vergleichbaren Quad-Core mit Windows 10 Pro X64 läuft...