OwnLVSelection - UDF für eigene Färbung der Selektion in Listviews

    • Offizieller Beitrag

    Hi,
    nach der FormatListview-UDF gibt es jetzt wieder etwas "Listviewmalerei". :D
    Den meisten von euch wird die monotone blaue Färbung von selektierten Listviewitem wohl auch nicht so gefallen. Ich habe nun eine UDF erstellt mit der man das für ein (bis 40 beliebig viele) Listview einer GUI völlig separat gestalten kann. Das basiert auf einem Workaround von Achilles aus dem Jahr 2008. Aber außer mir hatte wohl noch niemand Interesse, das in eine vernünftig zu händelnde Funktion zu packen.
    - Die verwendeten Listview müssen zwingend mit "GuiCtrlCreateListView" erstellt werden! Nur so gibt es eine ID, auf die auch aus der UDF heraus zugegriffen werden kann.
    - Wird ein Listview-Style bei der Erstellung des LV gesetzt, so ist dieser beim Registrieren des LV mit an die UDF zu übergeben (Ausnahme: Default-Style)
    - Für jedes registrierte Listview können eigene Selektionsfarben (Text/Hintergrund) gesetzt werden.
    - Die Standardfarben der Listview der GUI (gültig für alle registrierten LV) lassen sich ebenfalls setzen.
    - Es können registrierte LV auch wieder zurückgesetzt werden, sie erhalten dann die Standardfarben. werden dann wieder vom System gezeichnet und verhalten sich entsprechend (grau bei Fokusverlust). Der Style wird zurückgesetzt auf den Style bei Erstellung.
    Ein entscheidender Vorteil dieser Variante ist (wie ihr auf dem Bild sehen könnt): Auch nach Fokusverlust bleibt die Selektionsfärbung erhalten.

    Edit 24.10.2011: Kleine Änderungen - s. durchgestrichene bzw. blaue Bereiche in der Beschreibung vorab.

    OwnLVSelection(1.2).au3
    [autoit]

    #Region - TimeStamp
    ; 2011-10-24 12:05:40 v 1.2
    #EndRegion - TimeStamp
    #include-once
    #include <Array.au3>
    #include <GUIConstantsEx.au3>
    #include <GuiListView.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>

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

    Global Const $ODT_LISTVIEW = 102
    Global Const $ODA_DRAWENTIRE = 0x1
    Global Const $ODS_SELECTED = 0x0001

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

    ;===============================================================================
    ; Function Name....: _GuiCtrlListview_OwnSelectionAdd
    ; Description......: Registriert ein Listview für eigene Selektion
    ; Parameter(s).....: $hWnd Handle (oder ID) des Listview
    ; Requirement(s)...: Das Listview MUSS ZWINGEND mit "GuiCtrlCreateListView" erstellt werden!
    ; Return Value(s)..: Fehler @error - Handle/ID nicht vorhanden
    ; Author(s)........: BugFix ( [email='bugfix@autoit.de'][/email] )
    ;===============================================================================
    Func _GuiCtrlListview_OwnSelectionAdd($hWnd)
    Local $ret = __ManageSelection('add', $hWnd)
    If @error Then Return SetError(1)
    EndFunc ;==>_GuiCtrlListview_OwnSelectionAdd

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

    ;===============================================================================
    ; Function Name....: _GuiCtrlListview_OwnSelectionDel
    ; Description......: Listview nicht mehr in eigener Selektion zeichnen
    ; Selektion wird wieder vom System gezeichnet, graut aus bei Fokusverlust
    ; Parameter(s).....: $hWnd Handle (oder ID) des Listview
    ; Return Value(s)..: Fehler @error - 1 Handle/ID nicht vorhanden
    ; 2 Handle/ID nicht registriert
    ; Author(s)........: BugFix ( [email='bugfix@autoit.de'][/email] )
    ;===============================================================================
    Func _GuiCtrlListview_OwnSelectionDel($hWnd)
    Local $ret = __ManageSelection('del', $hWnd)
    If @error Then Return SetError(@error)
    EndFunc ;==>_GuiCtrlListview_OwnSelectionDel

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

    ;===============================================================================
    ; Function Name....: _GuiCtrlListview_OwnSelectionSetColor
    ; Description......: Text- und Hintergrundfarbe für die Selektion setzen
    ; Parameter(s).....: $hWnd Handle (oder ID) des Listview (-1 setzt die Farben für alle registrierten Listview)
    ; $iForeColor Textfarbe der Selektion (-1 setzt Default-Color)
    ; $iBackColor Hintergrundfarbe der Selektion (-1 setzt Default-Color)
    ; Return Value(s)..: Fehler @error - 1 Handle/ID nicht vorhanden
    ; 2 Handle/ID nicht registriert
    ; Author(s)........: BugFix ( [email='bugfix@autoit.de'][/email] )
    ;===============================================================================
    Func _GuiCtrlListview_OwnSelectionSetColor($hWnd=-1, $iForeColor=-1, $iBackColor=-1)
    Local $aParam[3] = [$hWnd, $iForeColor, $iBackColor]
    Local $ret = __ManageSelection('setcol', $aParam)
    If @error Then Return SetError(@error)
    EndFunc ;==>_GuiCtrlListview_OwnSelectionSetColor

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

    ;===============================================================================
    ; Function Name....: _GuiCtrlListview_OwnSelectionSetDefCol
    ; Description......: Setzen der Standardfarben (nicht selektierter Bereich) für alle Listview
    ; Parameter(s).....: $iForeColor Textfarbe nicht selektierter Bereich (Standard: schwarz)
    ; $iBackColor Hintergrundfarbe nicht selektierter Bereich (Standard: weiß)
    ; Return Value(s)..: keiner
    ; Author(s)........: BugFix ( [email='bugfix@autoit.de'][/email] )
    ;===============================================================================
    Func _GuiCtrlListview_OwnSelectionSetDefCol($iForeColor=0xFFFFFF, $iBackColor=0x000000)
    Local $aParam[2] = [$iForeColor, $iBackColor]
    __ManageSelection('defcol', $aParam)
    EndFunc ;==>_GuiCtrlListview_OwnSelectionSetDefCol

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

    ;===============================================================================
    ; Function Name....: Hilfsfunktion - __ManageSelection
    ; Description......: Verwaltung der Einstellungen
    ;===============================================================================
    Func __ManageSelection($sAction, $vParam='')
    Local Static $aHwnd[40][4], $iCurr = -1 ; [[hWnd, TxtCol, BackCol, OldStyle]]
    Local Static $aDefCol[2] = [0x000000,0xFFFFFF]
    Local $hLV, $index, $iFrom = 0, $iTo = $iCurr, $iStyle
    Switch $sAction
    Case 'add'
    $hLV = $vParam
    If Not IsHWnd($hLV) Then $hLV = GUICtrlGetHandle($hLV)
    If Not IsHWnd($hLV) Then Return SetError(1)
    If $iCurr = -1 Then GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")
    $iCurr += 1
    If $iCurr > 39 Then ReDim $aHwnd[$iCurr+1][4]
    $aHwnd[$iCurr][0] = $hLV
    $iStyle = GUICtrlGetStyle($hLV)
    $iStyle = Hex($iStyle[0],4)
    $aHwnd[$iCurr][3] = $iStyle
    GUICtrlSetStyle(_WinAPI_GetDlgCtrlID($hLV), BitOR($iStyle,$LVS_REPORT,$LVS_OWNERDRAWFIXED))
    Case 'del'
    $hLV = $vParam
    If Not IsHWnd($hLV) Then $hLV = GUICtrlGetHandle($hLV)
    If Not IsHWnd($hLV) Then Return SetError(1)
    $index = _ArraySearch($aHwnd, $hLV)
    If @error Then Return SetError(2)
    ; == Standardfarbe Systemmarkierung und Standardverhalten (Ausgrauen bei Fokusverlust)
    GUICtrlSetStyle(_WinAPI_GetDlgCtrlID($hLV), '0x' & $aHwnd[$index][3])
    $aHwnd[$index][0] = 0
    Case 'setcol'
    $hLV = $vParam[0]
    If $hLV <> -1 Then ; == -1 alle Werte setzen
    If Not IsHWnd($hLV) Then $hLV = GUICtrlGetHandle($hLV)
    If Not IsHWnd($hLV) Then Return SetError(1)
    $index = _ArraySearch($aHwnd, $hLV)
    If @error Then Return SetError(2)
    $iFrom = $index
    $iTo = $index
    EndIf
    If $iCurr < 0 Then Return SetError(2) ; == noch kein Fenster registriert
    If $vParam[1] = -1 Then $vParam[1] = $aDefCol[0]
    If $vParam[2] = -1 Then $vParam[2] = $aDefCol[1]
    For $i = $iFrom To $iTo
    $aHwnd[$i][1] = RGB2BGR($vParam[1])
    $aHwnd[$i][2] = RGB2BGR($vParam[2])
    Next
    Case 'getcol'
    $index = _ArraySearch($aHwnd, $vParam)
    If @error Then Return SetError(1)
    Local $aRet[2] = [$aHwnd[$index][1],$aHwnd[$index][2]]
    Return $aRet
    Case 'defcol'
    $aDefCol[0] = RGB2BGR($vParam[0])
    $aDefCol[1] = RGB2BGR($vParam[1])
    Case 'getdef'
    Return $aDefCol
    EndSwitch
    EndFunc

    [/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] [autoit][/autoit] [autoit]

    Func WM_DRAWITEM($hWnd, $Msg, $wParam, $lParam)
    Local $tDRAWITEMSTRUCT, $iBrushColor, $cID, $itmID, $itmAction, $itmState, $hItm, $hDC, $bSelected, $aCol, $aDefCol
    $tDRAWITEMSTRUCT = DllStructCreate("uint cType;uint cID;uint itmID;uint itmAction;uint itmState;" & _
    "hwnd hItm;hwnd hDC;int itmRect[4];dword itmData", $lParam)
    If DllStructGetData($tDRAWITEMSTRUCT, "cType") <> $ODT_LISTVIEW Then Return $GUI_RUNDEFMSG
    $cID = DllStructGetData($tDRAWITEMSTRUCT, "cID")
    $itmID = DllStructGetData($tDRAWITEMSTRUCT, "itmID")
    $itmAction = DllStructGetData($tDRAWITEMSTRUCT, "itmAction")
    $itmState = DllStructGetData($tDRAWITEMSTRUCT, "itmState")
    $hItm = DllStructGetData($tDRAWITEMSTRUCT, "hItm")
    $hDC = DllStructGetData($tDRAWITEMSTRUCT, "hDC")
    $aCol = __ManageSelection('getcol', $hItm)
    $aDefCol = __ManageSelection('getdef')
    If @error Then Return $GUI_RUNDEFMSG
    $bSelected = BitAND($itmState, $ODS_SELECTED)

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

    Switch $itmAction
    Case $ODA_DRAWENTIRE
    If $itmState = $bSelected Then
    $iBrushColor = $aDefCol[1]
    _WinAPI_SetTextColor($hDC, $aDefCol[0])
    Else
    $iBrushColor = $aCol[1]
    _WinAPI_SetTextColor($hDC, $aCol[0])
    EndIf
    Local $aBrush = DLLCall("gdi32.dll","hwnd","CreateSolidBrush", "int", $iBrushColor)
    Local $aBrushOld = _WinAPI_SelectObject($hDC, $aBrush[0])
    _WinAPI_FillRect($hDC, DllStructGetPtr($tDRAWITEMSTRUCT, "itmRect"), $aBrush[0])
    _WinAPI_SelectObject($hDC, $aBrushOld)
    _WinAPI_DeleteObject($aBrush[0])
    ; == Item
    Local $itmText = _GUICtrlListView_GetItemText($hItm, $itmID)
    DllStructSetData($tDRAWITEMSTRUCT, "itmRect", DllStructGetData($tDRAWITEMSTRUCT, "itmRect", 1) +5, 1) ; == Schrift 5px nach rechts
    DllStructSetData($tDRAWITEMSTRUCT, "itmRect", DllStructGetData($tDRAWITEMSTRUCT, "itmRect", 2) +2, 2) ; == Schrift 2px nach unten
    DllCall("user32.dll", "int", "DrawText", "hwnd", $hDC, "str", $itmText, "int", StringLen($itmText), _
    "ptr", DllStructGetPtr($tDRAWITEMSTRUCT, "itmRect"), "int", $DT_LEFT)
    ; == SubItem
    Local $iCol = _GUICtrlListView_GetColumnCount($hItm)
    If $iCol > 1 Then
    For $i = 1 To $iCol -1
    Local $iSubItmText = _GUICtrlListView_GetItemText($hItm, $itmID, $i)
    Local $aSubItmRect = _GUICtrlListView_GetSubItemRect($hItm, $itmID, $i)
    Local $iSubItmRect = DllStructCreate("int[4]")
    DllStructSetData($iSubItmRect, 1, $aSubItmRect[0] +5, 1)
    DllStructSetData($iSubItmRect, 1, $aSubItmRect[1] +2, 2)
    DllStructSetData($iSubItmRect, 1, $aSubItmRect[2], 3)
    DllStructSetData($iSubItmRect, 1, $aSubItmRect[3], 4)
    DllCall("user32.dll", "int", "DrawText", "hwnd", $hDC, "str", $iSubItmText, "int", StringLen($iSubItmText), _
    "ptr", DllStructGetPtr($iSubItmRect), "int", $DT_LEFT)
    Next
    EndIf
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc

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

    ; #FUNCTION# =========================================================================================================
    ; Name...........: GUICtrlGetStyle
    ; Description ...: Retrieves the Styles/ExStyles value(s) of the control.
    ; Syntax.........: GUICtrlGetBkColor($iControlID)
    ; Parameters ....: $iControlID - A valid control ID.
    ; Requirement(s).: v3.3.2.0 or higher
    ; Return values .: Success - Returns an Array[2] = [Style, ExStyle] with the Styles/ExStyles value(s).
    ; Failure - Returns an Array with -1 as the 0 & 1 Index's.
    ; Author ........: guinness & additional information from Melba23.
    ; Example........; Yes
    ;=====================================================================================================================
    Func GUICtrlGetStyle($iControlID)
    Local $aArray[2] = [-1, -1], $aExStyle, $aStyle, $hControl = $iControlID
    If Not IsHWnd($hControl) Then $hControl = GUICtrlGetHandle($iControlID)
    $aStyle = DllCall("user32.dll", "long", "GetWindowLong", "hwnd", $hControl, "int", 0xFFFFFFF0)
    If Not @error Then
    $aArray[0] = $aStyle[0]
    EndIf
    $aExStyle = DllCall("user32.dll", "long", "GetWindowLong", "hwnd", $hControl, "int", 0xFFFFFFEC)
    If Not @error Then
    $aArray[1] = $aExStyle[0]
    EndIf
    Return $aArray
    EndFunc ;==>GUICtrlGetStyle

    [/autoit]
    OwnLVSelection_Bsp(0.2).au3
    [autoit]

    #Region - TimeStamp
    ; 2011-10-24 00:42:01 v 0.2
    #EndRegion - TimeStamp
    #include <GuiListView.au3>
    #include "OwnLVSelection.au3"

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

    $gui = GUICreate('Bsp. OwnLVSelection', 430, 300)
    $cLV1 = GuiCtrlCreateListView('Spalte 1|Spalte 2', 10, 10, 200, 135)
    $hLV1 = GUICtrlGetHandle($cLV1)
    For $i = 1 To 20
    $index = _GUICtrlListView_AddItem($hLV1, 'Item-' & $i)
    _GUICtrlListView_AddSubItem($hLV1, $index, 'Item-' & $i & '-2', 1)
    Next
    _GuiCtrlListview_OwnSelectionAdd($hLV1)
    _GuiCtrlListview_OwnSelectionSetColor($hLV1, 0xFF55AA, 0xFFFF00)

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

    $cLV2 = GuiCtrlCreateListView('Spalte 1|Spalte 2', 220, 10, 200, 135)
    $hLV2 = GUICtrlGetHandle($cLV2)
    For $i = 1 To 20
    $index = _GUICtrlListView_AddItem($hLV2, 'Item-' & $i)
    _GUICtrlListView_AddSubItem($hLV2, $index, 'Item-' & $i & '-2', 1)
    Next
    _GuiCtrlListview_OwnSelectionAdd($hLV2)
    _GuiCtrlListview_OwnSelectionSetColor($hLV2, 0xFFFFFF, 0x0000FF)

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

    $cLV3 = GuiCtrlCreateListView('Spalte 1|Spalte 2', 10, 155, 200, 135)
    $hLV3 = GUICtrlGetHandle($cLV3)
    For $i = 1 To 20
    $index = _GUICtrlListView_AddItem($hLV3, 'Item-' & $i)
    _GUICtrlListView_AddSubItem($hLV3, $index, 'Item-' & $i & '-2', 1)
    Next
    _GuiCtrlListview_OwnSelectionAdd($hLV3)
    _GuiCtrlListview_OwnSelectionSetColor($hLV3, 0x222222, 0xCCCCCC)

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

    $cLV4 = GuiCtrlCreateListView('Spalte 1|Spalte 2', 220, 155, 200, 135)
    $hLV4 = GUICtrlGetHandle($cLV4)
    For $i = 1 To 20
    $index = _GUICtrlListView_AddItem($hLV4, 'Item-' & $i)
    _GUICtrlListView_AddSubItem($hLV4, $index, 'Item-' & $i & '-2', 1)
    Next
    _GuiCtrlListview_OwnSelectionAdd($hLV4)
    _GuiCtrlListview_OwnSelectionSetColor($hLV4, 0x1111FF, 0x00BBBB)

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

    GUISetState()

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

    Sleep(5000)
    _GuiCtrlListview_OwnSelectionDel($hLV4)

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

    Do
    Until GUIGetMsg() = -3

    [/autoit]


    autoit.de/wcf/attachment/14423/

  • Hi BugFix,

    Zunächst mal: Sehr schöne UDF, die ich auch schon das ein oder andere mal gebrauchen konnte :)
    Schade eigentlich dass sie so unbekannt ist. Ich denke gerade deswegen verzeiht man mir die Leichenschändung^^

    Grund warum ich schreibe ist dass es ein Problem gibt, wenn Scrollbalken vorhanden sind.
    Die Scrollbalken werden nach einem OwnSelectionAdd nicht mehr angezeigt. (Auch in deinem Beispiel)
    Behoben kann es durch ein Begin bzw Endupdate vor und nach Zeile 91

    [autoit]

    _GUICtrlListView_BeginUpdate($hLV)
    GUICtrlSetStyle(_WinAPI_GetDlgCtrlID($hLV), BitOR($iStyle,$LVS_REPORT,$LVS_OWNERDRAWFIXED))
    _GUICtrlListView_EndUpdate($hLV)

    [/autoit]

    Edit1 Zur Ergänzung:
    Auf das Problem ist Ram3000 gestoßen. Hier der Thread ;)
    [ offen ] ListView und Selected Item BGC