Listview Subitem BKColor anpassen - je Subitem eine Farbe

  • Hi @all

    ich kenn hier im Forum die nette Lösung von Bugfix, wie man jedem Feld eines Listviews eigene Farben zuordnen kann.
    Ich möchte (auch der Geschwindigkeit halber) eine extrem abgespeckte Lösung dessen verwenden.
    Ich erstelle eine Urlaubsliste, in der stehen links die Namen der Leute und ansonsten steht im Listview nichts drin, also alle Spalten (eine je Tag - 31 in der Darstellung) sind leer.
    Ich möchte direkt beim Erstellen eines Listviewitems in dieser Zeile das Subitem 5, 23,24 und 25 blau färben.
    Ich muss jedes dazu einmal ansteuern, das ist mir schon klar.
    Wie lässt sich dies mit möglichst wenig Programmschritten machen?

    Das Gesamte Listview muss nicht sortierfähig sein, ich benötige keine Textfärbung, Fontgröße, Art etc., ich benötige keine Default-Werte, die StandartListViewfärbung ist ok, es wird auch nicht aktualisiert, da die flüssigste Aktualisierung (z.B. der Benutzer schaltet die Darstellung auf den nächsten Monat) bei mir aus zwei ChildGUIs besteht, eine wird dargestellt, eine zweite ChildGUI wird ausgeblendet. Bei der Aktualisierung wird in der ausgeblendeten ein Listview erzeugt, dieses gefüllt - farbig angepasst und anschließend sichtbar gemacht. Dabei wird das bis dahin sichtbare ChildGUI ausgeblendet und das Listview darin deleted.
    Daher benötige ich auch keinen Firlefanz bei der Einfärbung der einzelnen SubItems - bei jeder Aktualisierung wird das gesamte Listview wieder entfernt.

    Kann mir jemand (Bugfix selbst vielleicht) eine Möglichkeit aufzeigen, das Subitem direkt nach dem Erzeugen des Items anzusprechen?
    Gibts da nen DLLCall oder an welcher Stelle des BugFix-Codes genau wird das Subitem gefärbt? Ich seh da immer nur nen Schwung DllStructGetData, aber keinen DLLCall, bei welchem das ganze wieder an das ListView übergeben wird.

    BspCode:

    [autoit]


    For $i = 1 To UBound($AWUeberblickMA,2)-1 ;Die MAs werden einzeln durchgegangen
    GUICtrlCreateListViewItem($i &"|" & $AWUeberblickMA[0][$i][1], $AWUeberblickLV[$AWUeberblickLV[7]+1]) ;Einbindung desListViewItems - bestehend aus dem Namen des MAs
    For $j = $Monatsstart To $Monatsende ;Die einzelnen Tage des Monats werden nach Werten durchsucht
    If $AWUeberblickMA[$j][$i][2] <> "" Then XXX (ListviewSubitem-BKColor einstellen) ;Wenn eine Farbe im MA-Array vorhanden ist, dann soll diese zum Einfärben verwendet werden
    Next
    Next

    [/autoit]
    • Offizieller Beitrag

    Gibts da nen DLLCall oder an welcher Stelle des BugFix-Codes genau wird das Subitem gefärbt? Ich seh da immer nur nen Schwung DllStructGetData, aber keinen DLLCall, bei welchem das ganze wieder an das ListView übergeben wird.


    :rolleyes: Nein, einen Dll-Call gibt es nicht. Es werden Strukturen verwendet und die Daten dadrin verändert.
    Wenn du eine fixe Anzahl an Elementen hast und nur Hintergrundfarben setzen möchtest geht das mit deutlich weniger Aufwand.
    Ich mach dir mal ein kleines Bsp. und stelle es rein.

    Edit: Und hier das Bsp.:

    Spoiler anzeigen
    [autoit]

    #include <GUIConstantsEx.au3>
    #include <GuiListView.au3>
    #include <ListViewConstants.au3>
    #include <StructureConstants.au3>
    #include <WindowsConstants.au3>

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

    $GUI = GUICreate("Listview Farbig", 800, 300)
    $cListView = GUICtrlCreateListView("", 2, 2, 796, 294, -1, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))
    $hListView = GUICtrlGetHandle($cListView)
    For $i = 1 To 31
    _GUICtrlListView_InsertColumn($hListView, $i-1, $i, 25)
    Next
    For $i = 0 To 21 ; alle Item/SubItem erstellen
    _GUICtrlListView_AddItem($hListView, "", $i)
    For $j = 0 To 30
    _GUICtrlListView_AddSubItem ($hListView, $i, "", $j)
    Next
    Next

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

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    GUISetState()

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

    While True
    $msg = GUIGetMsg()
    Switch $msg
    Case -3
    ExitLoop
    EndSwitch
    WEnd
    Exit

    [/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")
    Switch $hWndFrom
    Case $hListView
    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)
    ; Item/SubItem das aktuell gezeichnet werden soll ermitteln
    $iItem = DllStructGetData($tCustDraw, 'dwItemSpec')
    $iSubitem = DllStructGetData($tCustDraw, 'iSubItem')
    ; bei fixer Zuordnung z.B. so
    Switch $iItem ; Zeilenwahl
    Case 0, 5, 10, 15, 20 ; in 5-Zeilenabstand die Zeile rot
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR(0xFF0000))
    Case Else ; alle anderen weiß
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR(0xFFFFFF))
    EndSwitch
    Switch $iSubitem
    Case 5, 6, 12, 13, 19, 20, 26, 27 ; jede 6./7. Spalte blau
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR(0x0000FF))
    EndSwitch
    Return $CDRF_NEWFONT
    EndSwitch
    EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

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

    Func RGB2BGR($iColor)
    Local $sH = Hex($iColor,6)
    Return '0x' & StringRight($sH, 2) & StringMid($sH,3,2) & StringLeft($sH, 2)
    EndFunc

    [/autoit]
  • Hi BugFix,

    danke für deine schnelle Rückinfo - damit lässt sich doch bestimmt was anfangen...

    Zwei Frage hab ich da noch:
    1. Du hast im WM_Notify $iItem und $iSubItem nur als Ergebniss, nicht aber als Vorgabe drin. Ich muss nur programmtechnisch die Felder füllen, bei mir soll kein User da irgendwo hin klicken, damits bunt wird. Ich muss also direkt dem Programm mitteilen, z.B. $item 3, $subitem 25 muss rot sein. Dies muss ich auch nur ein einziges Mal je Listview machen - wie kann ich dies dem Programm beibringen?
    2. Geht das Ganze aufgrund 1. auch ohne WM_Notify, also direkt im Script-Ablauf? Hast da ne Idee? Man müsste doch die Strukturen 1x direkt nach dem Listviewcreate definieren können und dann während der Befüllung des Listviews verändern? Oder veranlasst die Veränderung der Befüllung den WM_Notify zur Ausführung? Dann müsste ich die Veränderung doch der entsprechenden Struktur mitteilen - nur wie?

    • Offizieller Beitrag

    Dann müsste ich die Veränderung doch der entsprechenden Struktur mitteilen - nur wie?


    Ja deshalb hatte ich in meiner Funktion ein Array erstellt, dass die Items führt, die zu färben sind und die zu verwendende Farbe.
    In der NOTIFY-Funktion hast du ja das Switch-Konstrukt, das du auf mehrer Listview erweitern kanns:

    [autoit]

    Switch $hWndFrom
    Case $hListView1

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

    Case $hListView2

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

    Case $hListView3

    [/autoit]

    Somit mußt du aber in deinem Array neben Item, SubItem und Farbe auch das Listview-Handle führen. ( $aLV[n][4] )
    Der Vorgang (innerhalb WM_NOTIFY-Funktion) ist immer identisch:
    - Handle = gesuchtes LV-Handle
    - Ereignis VOR Zeichnen Item/SubItem
    - Index Item/SubItem aus LV-Struktur auslesen
    - Prüfen ob Index/SubIndex in Array enthalten - JA: Werte in Struktur setzen

    Zitat

    2. Geht das Ganze aufgrund 1. auch ohne WM_Notify, also direkt im Script-Ablauf?


    Definitiv: Nein
    SubItems lassen sich nur per OWNERDRAW zeichnen. Nur kpl. Items kannst du wie bekannt einfärben.

  • ok, nur weiß ich jetzt immer noch nicht, wie ich in deinem konkreten Beispiel (ohne Klicken in das Listview) z.B. dem item 3, Subitem 14 sagen kann, färbe dich rot...

  • Hallo card0384,

    hier auf deine Vorgabe angepasst:

    Spoiler anzeigen
    [autoit]

    #include <GUIConstantsEx.au3>
    #include <GuiListView.au3>
    #include <ListViewConstants.au3>
    #include <StructureConstants.au3>
    #include <WindowsConstants.au3>

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

    $GUI = GUICreate("Listview Farbig", 1024, 300,0,0) ;<==== Breite geändert
    $cListView = GUICtrlCreateListView("", 2, 2, 1020, 294, -1, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT)) ;<==== Breite geändert
    $hListView = GUICtrlGetHandle($cListView)
    For $i = 1 To 31
    _GUICtrlListView_InsertColumn($hListView, $i-1, $i, 25)
    _GUICtrlListView_SetColumnWidth($hListView, $i-1,32) ;<==== eingefügt für Spaltenbreite
    Next
    For $i = 0 To 21 ; alle Item/SubItem erstellen
    _GUICtrlListView_AddItem($hListView, "", $i)
    For $j = 0 To 30
    _GUICtrlListView_AddSubItem ($hListView, $i, "", $j)
    Next
    Next

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

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    GUISetState()

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

    While True
    $msg = GUIGetMsg()
    Switch $msg
    Case -3
    ExitLoop
    EndSwitch
    WEnd
    Exit

    [/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")
    Switch $hWndFrom
    Case $hListView
    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)
    ; Item/SubItem das aktuell gezeichnet werden soll ermitteln
    $iItem = DllStructGetData($tCustDraw, 'dwItemSpec')
    $iSubitem = DllStructGetData($tCustDraw, 'iSubItem')
    ; bei fixer Zuordnung z.B. so
    Switch $iItem ; Zeilenwahl
    Case 0, 5, 10, 15, 20 ; in 5-Zeilenabstand die Zeile rot
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR(0xFF0000))
    Case Else ; alle anderen weiß
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR(0xFFFFFF))
    EndSwitch
    Switch $iSubitem
    Case 5, 23, 24, 25 ;<==== ;Spalte blau Vorgabe card0384
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR(0x0000FF))
    EndSwitch
    Return $CDRF_NEWFONT
    EndSwitch
    EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

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

    Func RGB2BGR($iColor)
    Local $sH = Hex($iColor,6)
    Return '0x' & StringRight($sH, 2) & StringMid($sH,3,2) & StringLeft($sH, 2)
    EndFunc

    [/autoit]

    Änderungen mit <======== kenntlich gemacht wichtig ist Zeile 61

    mfg (Auto)Bert

  • Hi AutoBert,

    danke für deine Antwort, aber die Zeile 61 erwartet ne Änderung im $iSubitem - da weiß ich derzeit noch nicht, woher ich die nehmen soll.
    Ich hatte eher mit ner Variante geliebäugelt, in der ich zwischen Zeile 10 und 19 den Wert für $iItem und $iSubItem und die Farbe angeben kann und damit die Änderung ausgelöst wird. Da fehlt mir noch der Ansatz dazu...

    Einmal editiert, zuletzt von card0384 (29. Juni 2010 um 10:10)

  • Hallo card0384,

    dann benutze doch eine Ini, damit du es nicht fest im Skript hinterlegen musst:

    Spoiler anzeigen
    [autoit]

    ;http://www.autoit.de/index.php?page…3432#post173432 BugFix
    #include <GUIConstantsEx.au3>
    #include <GuiListView.au3>
    #include <array.au3>
    #include <ListViewConstants.au3>
    #include <StructureConstants.au3>
    #include <WindowsConstants.au3>

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

    $aFormat = IniReadSection(@ScriptDir & "\LV_Format.ini","Format")
    _ArrayDelete($aFormat,0)
    _ArrayDisplay($aFormat)

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

    $GUI = GUICreate("Listview Farbig", 1024, 300, 0, 0) ;<==== Breite geändert
    $cListView = GUICtrlCreateListView("", 2, 2, 1020, 294, -1, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT)) ;<==== Breite geändert
    $hListView = GUICtrlGetHandle($cListView)
    For $i = 1 To 31
    _GUICtrlListView_InsertColumn($hListView, $i - 1, $i, 25)
    _GUICtrlListView_SetColumnWidth($hListView, $i - 1, 32) ;<==== eingefügt für Spaltenbreite
    Next
    For $i = 0 To 21 ; alle Item/SubItem erstellen
    _GUICtrlListView_AddItem($hListView, "", $i)
    For $j = 0 To 30
    _GUICtrlListView_AddSubItem($hListView, $i, "", $j)
    Next
    Next

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

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    GUISetState()

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

    While True
    $msg = GUIGetMsg()
    Switch $msg
    Case -3
    ExitLoop
    EndSwitch
    WEnd
    Exit

    [/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")
    Switch $hWndFrom
    Case $hListView
    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)
    ; Item/SubItem das aktuell gezeichnet werden soll ermitteln
    $iItem = DllStructGetData($tCustDraw, 'dwItemSpec')
    $iSubitem = DllStructGetData($tCustDraw, 'iSubItem')
    ; bei fixer Zuordnung z.B. so
    Switch $iItem ; Zeilenwahl
    Case 0, 5, 10, 15, 20 ; in 5-Zeilenabstand die Zeile rot
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR(0xFF0000))
    Case Else ; alle anderen weiß
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR(0xFFFFFF))
    EndSwitch
    Switch $iSubitem
    Case -1 ;kommt nicht vor ist aber notwendig, damit case else verwendet werden kann
    Case Else
    $iIndex = _ArraySearch($aFormat, $iSubitem, 0, 0, 0, 0, 1, 0)
    ConsoleWrite($iIndex & @CRLF)
    If $iIndex <> -1 Then DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR($aFormat[$iIndex][1]))
    EndSwitch
    Return $CDRF_NEWFONT
    EndSwitch
    EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

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

    Func RGB2BGR($iColor)
    Local $sH = Hex($iColor, 6)
    Return '0x' & StringRight($sH, 2) & StringMid($sH, 3, 2) & StringLeft($sH, 2)
    EndFunc ;==>RGB2BGR

    [/autoit]

    die dazugehörige INI:

    Code
    [Format]
    4=0x0000FF
    22=0x0000FF
    23=0x0000FF
    24=0x0000FF

    Achtung die Einträge beginnen bei 0 4= bedeutet also der 5. Tag des Monats

    mfg (Auto)Bert

  • ok, damit lässt sich was anfangen - wie bekomm ich nicht die Spalte, sondern nur ein bestimmtes Feld (Zeile 3 Spalte 5) farbig? Dein Script färbt immer die gesamte Spalte...

    • Offizieller Beitrag

    wie bekomm ich nicht die Spalte, sondern nur ein bestimmtes Feld (Zeile 3 Spalte 5) farbig?


    Schau dir doch mal mein Beispiel ab Zeile 53 an. Dort erfolgt die Zuordnung.
    Was du beachten mußt:
    Nach dem Setzen einer Farbe für ein Item wird dieser Farbwert für alle weiteren Item verwendet. Du mußt deshalb den Else-Zweig verwenden um den nicht betroffenen Elementen weiß als Hintergrund zu verpassen.

    Und wie du siehst, ist es nicht auf ein gaaanz simples Skript zu reduzieren. Eh du ewig probierst - verwende doch die UDF. ;)

  • Das würd ich gern - aber deine UDF verwendet Subroutinen (RGB-Farbe und WM_Notify), die ich bereits in meinem Programm enthalten habe.
    Dies macht es nicht unbedingt einfacher.

    PS: mein Programm liegt derzeit bei 15700 Zeilen (ohne die includes) - du siehst also, es ist leider nicht so einfach, einfach ein weiteres UDF einzubauen...

    dein Beispiel färbt doch auch erst eine ganze Zeile rot und dann eine ganze spalte blau. Dabei werden die rot-Anteile der Blauspalte überschrieben. Aber leider färbt dein Script keine einzelne Zelle.
    Ist eine einzelne Zelle überhaupt nicht ansteuerbar?

    Einmal editiert, zuletzt von card0384 (30. Juni 2010 um 14:59)

  • Hi Autobert und Bugfix,

    so, ich habe mir jetzt anhand von FormatSubItemLVex.au3 und den Array-Beschreibungen von Bugfix eine funktionierende Routine zusammengebaut, die genau das macht, was ich benötige:

    [autoit]


    Global $AWUeberblickLV[4] = ["","","",""]
    ;0 - ListView
    ;1 - ListView-Handle
    ;2 - ListView-Spalten
    ;3 - ListView-Formatset

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

    Func Abwesenheit aktualisieren()
    ...
    GUICtrlDelete($AWUeberblickLV[0])

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

    $AWUeberblickLV[0] = GUICtrlCreateListView($Text, 16, 16, $Breite, 544, -1, bitOr($LVS_EX_GRIDLINES, $LVS_EX_FLATSB))
    GUICtrlSetFont(-1, 9, 400, 0, "Microsoft Sans Serif")
    $AWUeberblickLV[1] = GUICtrlGetHandle($AWUeberblickLV[0])
    _GUICtrlListView_SetColumnWidth($AWUeberblickLV[0], 0, 0)
    $Breite1 = INT(($Breite-220)/($Ende-$Start))
    _GUICtrlListView_SetColumnWidth($AWUeberblickLV[0], 1, $Breite-50-($Breite1*($Ende-$Start)))
    For $i = 2 To $Ende-$Start+2
    _GUICtrlListView_SetColumnWidth($AWUeberblickLV[0], $i, $Breite1)
    Next
    $AWUeberblickLV[2] = _GUICtrlListView_GetColumnCount($AWUeberblickLV[0])
    ;Farbwerte füllen
    Dim $aSubItemSet[UBound($AWUeberblickMA,2)][$Ende-$Start+3]
    ;1.Dim - Zeile je MA
    ;2.Dim - Spalte (Zeitachse)
    ;Eintrag = Farbwert

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

    For $i = 1 To UBound($AWUeberblickMA,2)-1
    GUICtrlCreateListViewItem($i &"|" & $AWUeberblickMA[0][$i][1], $AWUeberblickLV[0])
    For $j = $Start-$AWUeberblickMA[0][0][4] To $Ende-$AWUeberblickMA[0][0][4]
    If $AWUeberblickMA[$j][$i][2] <> "" Then
    If $AWUeberblickMA[$j][$i][3] = 1 Then
    $aSubItemSet[$i][$j-($Start-$AWUeberblickMA[0][0][4])+2] = "0x"&StringRight($AWUeberblickMA[$j][$i][2], 6)
    Else
    $aSubItemSet[$i][$j-($Start-$AWUeberblickMA[0][0][4])+2] = "0x"&StringLeft($AWUeberblickMA[$j][$i][2], 6)
    EndIf
    EndIf
    $AWUeberblickLV[3] = $aSubItemSet
    Next
    Next
    ...
    EndFunc

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

    Func WM_NOTIFY($hWnd, $MsgID, $wParam, $lParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    If @error Then Return 0
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    ;If $icode = -5 Then ConsoleWrite($code)
    ; AND $icode = -101 Then $Clicked = True
    ;If NOT GUICtrlRead($wParam) = 0 AND $icode = -100 Then $LeerClicked = True
    If $icode = -5 AND $RightClick = False Then Return 0
    If NOT GUICtrlRead($wParam) = 0 AND $icode = -3 Then $DoubleClicked = True
    $AktObjekt = $wParam
    Switch $hWndFrom
    Case $AWUeberblickLV[1]
    Switch $iCode
    Case $NM_CUSTOMDRAW
    If Not _GUICtrlListView_GetViewDetails($hWndFrom) Then Return $GUI_RUNDEFMSG
    Local $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
    Local $iDrawStage, $iItem, $iSubitem, $hDC, $tRect, $aSubItemSet
    $iDrawStage = DllStructGetData($tCustDraw, 'dwDrawStage')
    Switch $iDrawStage
    Case $CDDS_ITEMPREPAINT
    Return $CDRF_NOTIFYSUBITEMDRAW
    Case BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM)
    $iItem = DllStructGetData($tCustDraw, 'dwItemSpec')
    $iSubitem = DllStructGetData($tCustDraw, 'iSubItem')
    $aSubItemSet = $AWUeberblickLV[3]
    $hDC = DllStructGetData($tCustDraw, 'hdc')
    If $iItem < UBound($aSubItemSet,1) AND $iSubitem < UBound($aSubItemSet,2) Then
    If $aSubItemSet[$iItem][$iSubitem] = "" Then $aSubItemSet[$iItem][$iSubitem] = 0xFFFFFF
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR($aSubItemSet[$iItem][$iSubitem]))
    Else
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR(0xFFFFFF))
    EndIf
    Return $CDRF_NEWFONT
    EndSwitch
    EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc

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

    Dies sind nur Auszüge aus meinem Programm, aber das Prinzip sollte ersichtlich sein.
    Ich hab die verschiedenen Farbstati in einer SQL-DB stehen, diese werden, falls Farbwerte für den jeweiligen Tag/Mitarbeiter vorhanden sind, in das Array geschrieben, welches dann (ohne Array-Search) direkt ausgewertet werden kann. Ich konnte mein WM_NOTIFY dahingehend anpassen, daß es sowohl Doppel-Klick (für meine anderen Funktionalitäten) wie auch die Befärbung der Tabelle übernimmt.

    Ich habe jetzt auch das Prinzip verstanden, man kann den einzelnen Wert nicht direkt ansprechen, sondern muss warten (millisekunden :) ), bis das System das entsprechende Tabellenfeld selbst auf Aktualisierung anspricht, hakt dabei ein und verändert die Werte - stimmt das so?

    Jetzt hätte ich noch zwei Ergänzungsfragen.

    1: wie muss ich das WM_NOTIFY anpassen, damit ich im Falle des Doppelklicks für die Tabelle den Wert für $item und $subitem zurückbekomme?
    Ich hab aus LV_Edit_Subitem den entsprechenden Codeschnippsel und mein WM_Notify übernommen, bekomme aber nur die Spalte, nicht die Zeile zurück - siehe hier - alles unter Case $NM_DBLCLK:

    [autoit]


    Func WM_NOTIFY($hWnd, $MsgID, $wParam, $lParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    If @error Then Return 0
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    ;If $icode = -5 Then ConsoleWrite($code)
    ; AND $icode = -101 Then $Clicked = True
    ;If NOT GUICtrlRead($wParam) = 0 AND $icode = -100 Then $LeerClicked = True
    If $icode = -5 AND $RightClick = False Then Return 0
    If NOT GUICtrlRead($wParam) = 0 AND $icode = -3 Then $DoubleClicked = True
    $AktObjekt = $wParam
    Switch $hWndFrom
    Case $AWUeberblickLV[1]
    Switch $iCode
    Case $NM_CUSTOMDRAW
    If Not _GUICtrlListView_GetViewDetails($hWndFrom) Then Return $GUI_RUNDEFMSG
    Local $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
    Local $iDrawStage, $iItem, $iSubitem, $hDC, $tRect, $aSubItemSet
    $iDrawStage = DllStructGetData($tCustDraw, 'dwDrawStage')
    Switch $iDrawStage
    Case $CDDS_ITEMPREPAINT
    Return $CDRF_NOTIFYSUBITEMDRAW
    Case BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM)
    $iItem = DllStructGetData($tCustDraw, 'dwItemSpec')
    $iSubitem = DllStructGetData($tCustDraw, 'iSubItem')
    $aSubItemSet = $AWUeberblickLV[3]
    $hDC = DllStructGetData($tCustDraw, 'hdc')
    If $iItem < UBound($aSubItemSet,1) AND $iSubitem < UBound($aSubItemSet,2) Then
    If $aSubItemSet[$iItem][$iSubitem] = "" Then $aSubItemSet[$iItem][$iSubitem] = 0xFFFFFF
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR($aSubItemSet[$iItem][$iSubitem]))
    Else
    DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR(0xFFFFFF))
    EndIf
    Return $CDRF_NEWFONT
    EndSwitch
    Case $NM_DBLCLK
    Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $lParam)
    Local $aInfo[5] = [$hWndFrom, $iIDFrom, $iCode, DllStructGetData($tInfo, "Index"), _
    DllStructGetData($tInfo, "SubItem")]
    ConsoleWrite(@CRLF)
    For $i = 0 To UBound($aInfo)-1
    ConsoleWrite($i & "-" & $aInfo[$i] & " - ")
    Next
    EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc

    [/autoit]


    Edit: habs inzwischen rausgefunden, es liegt am Ex-Style bitOr($LVS_EX_GRIDLINES, $LVS_EX_FLATSB). Sobald ein Ex-Style angegeben wird, kommt die Zeile nicht mehr zurück. Ich bekomm nur die Zeile, wenn ich in der ersten Spalte direkt auf den Texteintrag dblklicke. Bei allen anderen Spalten kommt nichts zurück, zumal ja auch nichts drin steht...
    Mit $LVS_EX_FULLROWSELECT komm ich wieder an die Zeile ran, dann ist aber die betreffende Zeile blau (markiert). Dies nützt mir auch nichts - wenn überhaupt, sollte max. das angeklickte Feld markiert sein - es würde mich aber auch nicht stören, wenn gar nichts markiert ist. Gibts da ne Möglichkeit, dennoch an die Zeile ranzukommen?

    Edit: Wenn ich bei $iCode den Switch nach Case -100 erweitere, dann komm ich, bevor die Zeile markiert wird, an $item ran.
    Gibts da ne Möglichkeit, nachdem ich den $item-Wert ausgelesen habe, das Markieren der Zeile zu unterbinden?


    2: ist es über diese Variante möglich (falls ja wie), die Gridlines manuell zu befüllen? Ich stelle mir vor, nur die Felder zu befüllen, die zum Array gehören, also wo auch Werte vorkommen können, und dabei der Übersichtlichkeit halber nur jede 7.Spalte und nur jede 2. Zeile mit Gridlines zu bestücken. Wenn ich mittels DllStructSetData($tCustDraw, 'clrTextBk'... den Hintergrund verändern kann, gibt es doch bestimmt einen anderen Wert, mit dem ich z.B. den unteren Rand des Feldes mit einer bestimmten Strichstärke und Farbe bestücken kann.
    Gibts da Links zu MS, wo die Werte, wie z.B. 'clrTextBk' und die anderen Werte beschrieben werden?

    5 Mal editiert, zuletzt von card0384 (2. Juli 2010 um 13:51)

  • Es taucht noch ein Problem auf, wenn ich das Script laufen lasse und mir dabei eine Tabelle mit 365 Tagen = Spalten anzeigen lasse, wird das Script ca. ab der 5. Zeile extrem langsam. Wo kann man da noch etwas verbessern (speziell im WM_Notify)?

    • Offizieller Beitrag

    Nur mal kurz:
    Mit OWNERDRAW kannst du ausschließlich selbst gestalten: Font, TextColor, BkColor. Strichstärken der Gridlines kannst du nicht gestalten.
    Ein Listview mit 365 Spalten hat natürlich 365*Zeilenzahl einzelne Zellen. Wenn das Verarbeiten der Infos für eine Zelle nur eine ms dauert, sind das bei 10 Zeilen schon über 3 Sekunden Aktualisierungsdauer.
    Ich würde nur einen Monat +/- einer Dekade darstellen.

  • Ich hab das ganze noch ein wenig analysiert.
    Ich konnte feststellen, daß die meiste Zeit (und Prozessorlast) draufgeht beim DllStructSetData($tCustDraw, 'clrTextBk', "Farbe").
    Ich habe darauf hin den Weissanteil optimiert, jetzt läuft das Script doch recht flüssig und ohne nennenswerte Prozessorlast.
    Hier die simple Erweiterung als Beispiel, sollte Bugfix eventuell in Ansätzen in sein Beispielscript übernehmen (die Farbe wirste wohl mit deiner DefaultColor ersetzen...):

    [autoit]


    If DllStructGetData($tCustDraw, 'clrTextBk') <> 0xFFFFFF Then DllStructSetData($tCustDraw, 'clrTextBk', RGB2BGR(0xFFFFFF))

    [/autoit]

    Ich hab auch inzwischen ne etwas tricky-Variante gefunden, ohne die Listview-Zeile zu markieren, an die Werte für Zeile und Spalte ranzukommen:
    Listviewcreate mit $LVS_EX_FULLROWSELECT und

    [autoit]


    Case $NM_DBLCLK
    Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $lParam)
    Local $aInfo[2] = [DllStructGetData($tInfo, "Index"), DllStructGetData($tInfo, "SubItem")]
    $AWUeberblickLV[5] = $aInfo
    $DoubleClicked = True
    Case -100
    Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $lParam)
    $AWUeberblickLV[4] = DllStructGetData($tInfo, "Index")
    Case -101
    If $AWUeberblickLV[4] > -1 Then _GUICtrlListView_SetItemFocused($AWUeberblickLV[1], $AWUeberblickLV[4], False)

    [/autoit]

    So richtig gefällt mir die Lösung aber nicht. Ich habe aber analysiert und festgestellt, daß bei keinem Casewert in der $tInfo-Struktur die Zeile zu finden ist, wenn nicht $LVS_EX_FULLROWSELECT als ex-Schalter gesetzt ist (wenn irgend ein anderer Ex-Schalter gesetzt wird). Hat da jemand noch eine bessere Idee?

    2 Mal editiert, zuletzt von card0384 (5. Juli 2010 um 17:19)