ListView - SubItem einzeln färben/formatieren, Finale Version! (v1.3)

  • Hi,
    ich denke, dass ihr sicherlich reichlich Anwendung für dieses Workaround diese UDF finden werdet.
    Mit den Standardfunktionen ließen sich ja nur abwechselnd die Zeilen einfärben. Nun habt ihr folgende Möglichkeiten:
    - jedes SubItem einzeln färben (TextColor, BackColor) und
    - formatieren (Größe, Weite, Schriftart etc....)


    Edit 30.08.2009
    Hab das nochmal etwas überarbeitet und ein Problem gefixed. Die in IParam gespeicherten Werte konnten mit Control-IDs kollidieren. Das ist jetzt behoben.
    Die wesentlichen Punkte im Skript sind kommentiert, damit ihr nachvollziehen könnt, was passiert.


    Edit 27.09.2009
    Ich habe nochmal zugeschlagen :D
    - keine Begrenzung der Spaltenzahl mehr!
    - Auch bei mehreren Listview werden alle Formatierungsdaten in einem Array verwaltet
    - die Prüfung, ob ein (Sub)Item formatiert ist, läuft wesentlich schneller
    - Management zur Verwaltung der Formatinfos zu den Items ist integriert (UDF-Funktionen angepaßt)
    - Listview kann sortiert, Einträge können eingefügt, gelöscht werden etc.


    autoit.de/wcf/index.php?attachment/5913/


    Finale Version (30.09.09)
    So, nun bin ich wohl endlich bei der endgültigen Version angelangt. 8o


    Der User braucht nun keine Handstände mehr zu machen. Alles Lästige ist in eine Include-Datei ausgelagert. Auch WM_NOTIFY. Die Funktionsnamen habe ich analog zu denen der Listview-UDF erstellt. Ich habe als Standard eingerichtet, dass mit Klick auf die Spalte sortiert werden kann.


    Edit 06.08.11
    Nach langer Zeit mal wieder einige kleine Änderungen:
    1. Da alle Funktionen ausgelöst werden durch Auswertung von $WM_NOTIFY, mußten eigene Auswertungen ins Include geschrieben werden -- schlecht :huh:
    Jetzt hooke ich die Message, sodass $WM_NOTIFY ganz normal mit GuiRegisterMsg registriert und verwendet werden kann.


    2. Es wird jetzt eine Globale Variable ( $FORMATLV_aITEM_INDEX ) bereitgestellt, die mit den Formatinformationen des per Rechtsklick markierten SubItem befüllt ist.
    Inhalt: [Status geklickt:True/False, $hWndFrom, "Index", "SubItem", $iBkCol, $iCol, $iSize, $iWeight, $sFont]. Verwendung s. Func _RightClick() im Bsp.-Skript.


    3. Die Funktion _GUICtrlListView_Formatting_Shutdown() braucht nicht mehr ins Skript eingebaut werden, da sie jetzt beim Beenden des Skripts automatisch aufgerufen wird.


    Die alten Versionen habe ich jetzt entfernt.


    Edit 08.08.2011
    Und noch etwas geschraubt:
    1. Zum Erstellen der Listvieweinträge (_GUICtrlListView_AddOrIns_Item) kann jetzt auch ein Array übergeben werden.
    Im Test hatte ich für 10.000 Item (6 spaltig) mit Einzelaufruf 2.241 sec benötigt. Bei Übergabe mit Array schrumpfte das auf 87 sec.
    Ich benötige jetzt also <4 % der Zeit, das nenn ich eine gelungene Einsparung. Hauptbremse war natürlich ReDim - sollte man immer sehr sparsam verwenden.


    2. Die Performance sollte jetzt auch etwas flüssiger sein. Ich habe Abfragen eingefügt, sodass Neuzeichnungen nur erfolgen, wenn eine Änderung zum vorhergehenden Element besteht.


    3. Die Funktion _GUICtrlListView_DefaultsGet() habe ich noch hinzugefügt. War schon im letzten Anhang dabei, hatte ich nur vergessen zu erwähnen.
    Damit können die Standardformatierungswerte ausgelesen werden. [$iBkCol, $iCol, $iSize, $iWeight, $sFont]


    Eine Funktion zum Spalten einfügen wird es vermutlich nicht geben. Um das realisieren zu können, müßte ich wohl mein Programmkonzept völlig neu gestalten, d.h. alles nochmal neu entwickeln. In den bisherigen Ablauf läßt sich diese Funktion nicht sinnvoll einbringen.


    Edit 10.08.2011
    Fix: Beim Einfügen eines Arrays neuer Item, wurde die Reihenfolge der eingefügten Item vertauscht, v1.3 aktualisiert


    Hier die Funktionen:


    Initialisierung beim Start (nach Erstellung der GUI)
    _GUICtrlListView_Formatting_Startup($GUI, $hListView)
    $GUI Handle der GUI
    $hListView Listview Handle, bei mehreren LV die Handle als Array übergeben


    Ressourcen löschen am Skriptende
    _GUICtrlListView_Formatting_Shutdown() erfolgt jetzt automatisch mit Beendigung des Skripts


    Neue Listvieweinträge an- oder einfügen
    _GUICtrlListView_AddOrIns_Item($hWnd, $vText, $iItem=-1)
    $hWnd Listview Handle
    $vText einfacher String um nur das Item zu setzen (dann muß SubItem mit _GUICtrlListView_AddSubItem gesetzt werden)
    oder
    "Item|SubItem|SubItem.." um Item und alle SubItem auf einmal zu setzen
    oder
    ein Array mit derartigen Strings
    $iItem Item Index, mit -1 wird das neue Item am Ende angefügt (Standard)
    sonst
    das Item wird an der Indexposition eingefügt

    Löschen von einem, markierten oder allen Item:

    _GUICtrlListView_FormattedDeleteItem($hWnd, $iIndex)
    _GUICtrlListView_FormattedDeleteItemsSelected($hWnd)
    _GUICtrlListView_FormattedDeleteAllItems($hWnd)


    Standards zur Formatierung setzen/abfragen

    _GUICtrlListView_DefaultsSet($iBkCol=0xFFFFFF, $iCol=0x000000, $iSize=14, $iWeight=400, $sFont='Arial')
    $iBkCol back color Standard: weiß
    $iCol text color Standard: schwarz
    $iSizefont size Standard: 14
    $iWeight font weight Standard: 400
    $sFontfont name Standard: Arial


    _GUICtrlListView_DefaultsGet()
    Return: [$iBkCol, $iCol, $iSize, $iWeight, $sFont]


    (Sub)Item Formatieren
    _GUICtrlListView_FormattingCell($hWnd, $iItem, $iSubItem, $iBkCol=-1, $iCol=-1, $iSize=-1, $iWeight=-1, $sFont=-1)
    $hWnd Listview Handle
    $iItem Item Index
    $iSubItem SubItem Index
    $iBkCol back color (-1 = default BkCol)
    $iCol text color (-1 = default txtCol)
    $iSize height of font (-1 = 14)
    $iWeight font weight (-1 = 400)
    $sFont typefont name (-1 = Arial)



    Edit
    Habe noch ein Skript erstellt um die Funktionen den Calltipps von SciTE hinzuzufügen.


    Edit 08.04.2012
    Mit AutoIt-Version3.3.8.0 ist folgende Änderung erforderlich:
    ; statt:
    $FORMATLV_oPARAM_SEARCH.Add( ..., ...)
    $FORMATLV_oPARAM_SEARCH.Item( ..., ...)
    $FORMATLV_oPARAM_SEARCH.Remove( ..., ...)


    ; den ersten Parameter als String übergeben:


    $FORMATLV_oPARAM_SEARCH.Add( String(...), ...)
    $FORMATLV_oPARAM_SEARCH.Item( String(...), ...)
    $FORMATLV_oPARAM_SEARCH.Remove( String(...), ...)



  • Im großen und ganzen funktioniert alles.Das einzige ist, das die Farbänderung beim mir erst wirksam wird ,wenn ich durch das LIstview scrolle. Kann aber nicht genau sagen ob das jetzt eventuell an Vista liegt. Habe gerade keinen anderen Rechner zum testen .


    Edit: Habe den Fehler gefunden .


    Folgenden Code :
    _WinAPI_PostMessage($hListView, $LVM_UPDATE, 0, 0)

    gegen diese ersetzen :
    _WinAPI_InvalidateRect($hListView)


    Hier mal der geänderte Scriptcode


    Kannst ja mal schauen ob das ganze für WinXp auch gilt. Sonst wie immer 1A Arbeit :thumbsup::thumbup:

  • Danke Raupi für den Tipp. Werde die Änderung einfügen, dann ist es universell.
    Ich werde sowieso noch versuchen, die Parametereingabe für den Font zu vereinfachen. Dieser 14-Parameter String, von dem man auch alle setzen muß, wenn man eine andere Schriftart wählen will, da diese blöderweise der letzte Parameter ist, ist mir etwas zu stressig.
    Ich habe auch festgestellt, dass die Parameter für italic, strike, underlined ohne Wirkung bleiben. Und die anderen Parameter (precision etc.) verwendet doch wohl auch niemand. Am Besten, ich lasse diesen Format-String und einen kürzeren Alternativ-String zu. Ich probier mal. Das Ergebnis poste ich dann.

  • Hallo BugFix,


    nette Funktionen, aber irgendwie stimmt da was nicht mit deinen Dateien.


    Du schreibst, daß die aktuellste Version in der Datei "FormatSubItemLV_new.au3" zu finden ist. Die ist aber viel kleiner als "FormatSubItemLVex.au3" (10 anstatt 18kb).
    Obendrein ist nichts kommentiert und es fehlen Funktionen, wie z.B. _OneRowSetCol.


    Ist das Absicht, oder Versehen?


    Besten Dank im voraus und weiterhin happy computing!
    R@iner

  • Du schreibst, daß die aktuellste Version in der Datei "FormatSubItemLV_new.au3" zu finden ist. Die ist aber viel kleiner als "FormatSubItemLVex.au3" (10 anstatt 18kb).
    Obendrein ist nichts kommentiert und es fehlen Funktionen, wie z.B. _OneRowSetCol.

    Ja klar ist die neueste Version viel kleiner, habe ich doch auch geschrieben:

    Zitat

    Code ist kürzer und schneller. s. Post 1, Bsp.: FormatSubItemLV_new.au3


    Mit der Funktion:
    _SetItemParam($hWnd, $iItem, $iSubItem, $iBkCol=-1, $iCol=-1, $iSize=-1, $iWeight=-1, $sFont=-1)
    kannst du alle notwendigen Einstellungen vornehmen, also Einzelzelle, Zeile oder Spalte formatieren. Mußt sie halt notwendigerweise in einer Schleife mehrfach ausführen.

  • Hallo BugFix,


    das hab ich alles gelesen, trotzdem hat es mich gewundert, das die letzte Version abgespeckt und vor allem ohne Kommentare war. Egal.


    Ich hab Dein Script jetzt mal als Basis genommen um zu verstehen, wie das colorieren funktioniert. So richtig verstanden habe ich es nicht, aber den Aufruf von _SetItemParam hab ich verstanden. :)


    Mein eigentliches Ziel ist es, in meiner Tabelle (ca. 70 Zeilen, 15 Spalten), jede zweite Reihe farbig mit einer Farbe zu versehen. Font ist mir derzeit nicht wichtig.


    Ich hab jetzt mal dein Script genommen und es etwas erweitert, allerdings ist das Scrollen der Listen, egal ob horizontal oder vertikal, sehr träge.
    Deaktiviere ich den WM_NOTIFY, werden die Felder logischerweise nicht mehr farbig gemacht, aber der Geschwindigkeitsunterschied ist schon sehr deutlich.
    Gut, mein Rechner ist alt, aber vielleicht haste noch ne Idee, wo man was noch schneller machen könnte.


    Hier mein Wurf:



    Besten Dank im voraus!
    R@iner

  • jede zweite Reihe farbig mit einer Farbe zu versehen. Font ist mir derzeit nicht wichtig.


    Also das Ziel erreichst du ohne meine Formatfunktion. Das geht schon seit geraumer Zeit standardmäßig:
    #include <GuiListView.au3>
    #include <GUIConstantsEx.au3>
    GUICreate('Test')


    $ListView1 = GUICtrlCreateListView("Spalte 1|Spalte 2", 15, 15, 300, 250)
    GUICtrlSetBkColor(-1, 0xFF4400) ; Farbe ungerade Zeilen
    GUICtrlSetBkColor(-1, $GUI_BKCOLOR_LV_ALTERNATE)
    _GUICtrlListView_SetColumnWidth($ListView1, 0, 148)
    _GUICtrlListView_SetColumnWidth($ListView1, 1, 148)


    For $i = 1 To 10
    GUICtrlCreateListViewItem(Random(10000, 1000000, 1) & '|' & Random(10000, 1000000, 1), $ListView1)
    GUICtrlSetBkColor(-1, 0xFFFF23) ; Farbe gerade Zeilen
    Next


    GUISetState()


    Do
    Until GUIGetMsg() = -3

  • Hallo BugFix,


    danke für deine Antwort. Ich hab mich wohl etwas unglücklich ausgedrückt. Besser sollte es heissen:


    Mein eigentliches Ziel ist es, in meiner Tabelle (ca. 70 Zeilen, 15 Spalten), jede zweite Reihe farbig mit irgendeiner Farbe zu versehen. Nicht abwechselnd 2 Farben.
    Z.B. Zeile 1 in rot, Zeile 2 weiß, Zeile 3 orange, Zeile 4 weiß, Zeile 5 in grün, ....


    Und genau dafür brauche ich deinen Lösung, oder kann man das anders auch lösen?


    Happy computing!
    R@iner

  • Und genau dafür brauche ich deinen Lösung, oder kann man das anders auch lösen?


    Ja, kann man. Da ist es nicht nötig für jede Zelle die Werte zu hinterlegen. Es wird einfach der Farbwert für die Zeile in einem Array hinterlegt:


  • ,Super UDF kann ich brauchen

    Mfg.simon

    Zitat

    Copyright hinweise und sonstige Hinweise des Autors sind dringenst zu Beachten !!!

    Momentane Projekte & Co.
    - Visual C++ bzw. Borland C++ lernen
    - "Packprogramm" in AutoI

  • Hallo Bugfix,


    vielen herzlichen Dank für den neuen Code!


    Ich habe ihn mal mit mehr Reihen und Spalten versehen. Aber auf meinem 1,8 GHz P4 ist das Scrollen grausam rucklig und sehr langsam :( Speziell horizontal, also links-rechts. Von der Geschwindigkeit an meinem Notebook, P3, 648 Mhz will ich erst garnicht reden.



    Wenn ich dagegen auf die 2 Farben-Lösung umsteigen würde, wie Du es auch oben schon mal vorgeschlagen hast, dann habe ich keine Ruckler und alles geht zügig.


    Hier mal ein Vergleich mit gleicher Anzahl an Reihen und Spalten.



    Ich würde schon gerne Deine Mehrfarbenlösung benutzen. Hast Du noch ne Idee, wie man das beschleunigen kann?


    Besten Dank und viele Grüße!
    R@iner


    PS. Weißt Du warum am Ende meines zweiten Beispiels unten ein Leerzeile sichtbar ist?

  • Ich würde schon gerne Deine Mehrfarbenlösung benutzen. Hast Du noch ne Idee, wie man das beschleunigen kann?

    Ich sehe hier leider kein Potential, das weiter zu beschleunigen. Das Problem liegt dadrin, dass bei jedem Zeichnen des Item die Aufrufe zum Zeichnen neu erfolgen müssen.

    PS. Weißt Du warum am Ende meines zweiten Beispiels unten ein Leerzeile sichtbar ist?

    Seltsam, wenn ich das Bsp. ausführe, ist dort keine Leerzeile. ?(


    P.S. Auf meinem lahmen Schleppi (Intel Celeron; 1,5 GHz; 448 MB RAM) läuft das recht zügig. Ja, es ruckelt - aber nicht so, dass ich Augenkrebs bekomme. :D


    Edit:
    Hatte gar nicht bedacht, dass du ja die Fontfunktionen nicht benötigst. Habe WM_NOTIFY jetzt mal etwas gekürzt. Könnte noch ein bischen Performance bringen.


    Zitat von skyteddy

    Ich hab Dein Script jetzt mal als Basis genommen um zu verstehen, wie das colorieren funktioniert. So richtig verstanden habe ich es nicht

    Ist gar nicht so schwer, wenn auch nicht unbedingt offensichtlich. ;)
    Passiert alles in WM_NOTIFY:
    $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
    Hier wird die Struktur $tCustDraw befüllt mit den Werten vom Pointer $lParam (für das aktuelle ListViewItem).
    Werden jetzt Werte in dieser Struktur geändert, so sind diese sofort gültig.
    Das passiert für die Hintergrundfarbe in folgendem Befehl:
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR($aColor[$iItem]))

  • Hallo BugFix,


    danke Dir für deine Beschleunigung. Es ist schon viel besser. Ich werd das heute mal austesten und schauen, ob das flüssig genug ist.


    Mir war dann schon klar, daß die eigentliche Funktion das WM_NOTIFY ist. In dem von mir fälschlich ausgewähltem alten Beispiel von Dir gibt es aber viele Funktionen drumherum. Aber das ist ja nicht mehr notwendig :) Ich kann mir jetzt auch ungefähr zusammenreimen, was die WM_NOTIFY macht.


    Nochmal zu Deinem Beispiel zurück und meiner Leerzeile. In Deinem Original-Beispiel mit der einfachen toogle-Variante ist es bei 10 Zeilen sogar ein großer Leerbereich unten.
    Das verstehe ich ja noch, da das ListView größer ist und die 10 Zeilen den Bereich nicht einnehmen. Erhöhe ich aber die Zeilenanzahl sehe ich trotzdem einen Leerbereich. Leerzeile ist wohl wieder unglücklich ausgedrückt. Besser ist Leerbereich.


    Hier das Beispiel:


    Hier mal ein Screenshot:
    autoit.de/wcf/index.php?attachment/5414/
    Woher kommt dieser Leerbereich?


    Happy computing!
    R@iner

  • Woher kommt dieser Leerbereich?


    Sieht mir rein optisch aus wie die Hintergrundfarbe des Controls.


    Genauso ist es, die Hintergrundfarbe des Controls ist natürlich sichtbar auch wenn kein weiteres Item folgt. Solange Platz da ist, wird er auch eingefärbt.
    Besonders deutlich wird das, wenn du die Spaltenbreite verringerst. (s. Bild)
    Allerdings habe ich diesen Leerbereich nach unten nur dann, wenn es weniger Item sind, als im LV-Bereich dargestellt werden könnten. Also wenn die vertikale Scrollleiste sichtbar ist, ist bei mir dieser Effekt aufgehoben.


    autoit.de/wcf/index.php?attachment/5415/

  • Hallo Zusammen,


    ja, es scheint die Hintergrundfarbe zu sein. Wenn die die Höhe des ListViewControlls verändere, dann paßt es irgendwann.


    Eine abschließende Frage habe ich jetzt noch, bevor ich alles in meinem ursprünglichen Programm ändern muß.


    Derzeit benutze ich
    GUICtrlCreateListView
    _GUICtrlListView_InsertColumn
    _GUICtrlListView_AddItem


    Wenn ich jetzt die abwechselnden Farben benutzen will, muß ich mein Script auf
    GUICtrlCreateListViewItem
    umstellen, oder?


    Ich habe keine vergleichbaren Funktionen gefunden und in meinem Schnelltest ging das colorieren bei den oben genannten Befehlen mit
    GUICtrlSetBkColor(-1, 0xFFFF23) ; Farbe gerade Zeilen
    nicht


    Happy computing!
    R@iner