Jump to content

ListView CustomDraw highlighted row that stays when no selection is made


DavidStark
 Share

Recommended Posts

Hey guys,

After much searching and reading I Siao's example script from the below link is the closest to what I need to do.

I have a ListView that is populated with the names of different configurations.  When a Listview item is selected, a form is populated with that items data.  Right now I have a column that shows which item's data is shown in the form, but it would be much cleaner to just have the current item highlighted.

My problem is this - The highlighting in Siao's example works great, but inside the Listview when you select in the "empty" space to essentially deselect everything the highlighting disappears.

How can I keep the last selected item highlighted when clicking in this empty space?

Also - I do not understand enough about Windows notifications to understand if we could utilize SendMessage to initiate a custom draw....  It seems to me that you could specify an item and then invoke the DLL function to redraw the item that you specified with the colors that you specified.... That's the idea I get when I read the MSDN documentation on it: https://msdn.microsoft.com/en-us/library/windows/desktop/ff919573(v=vs.85).aspx

 

Siao's Example modified for latest AutoIt:

#Include <GuiConstantsEx.au3>
#Include <GuiListView.au3>
#include <WindowsConstants.au3>
#cs
;custom draw constants
Global Const $CDDS_ITEM = 0x10000
Global Const $CDDS_MAPPART = 0x5
Global Const $CDDS_POSTERASE = 0x4
Global Const $CDDS_POSTPAINT = 0x2
Global Const $CDDS_PREERASE = 0x3
Global Const $CDDS_PREPAINT = 0x1
Global Const $CDDS_SUBITEM = 0x20000
Global Const $CDDS_ITEMPOSTERASE = BitOR($CDDS_ITEM, $CDDS_POSTERASE)
Global Const $CDDS_ITEMPOSTPAINT = BitOR($CDDS_ITEM, $CDDS_POSTPAINT)
Global Const $CDDS_ITEMPREERASE = BitOR($CDDS_ITEM, $CDDS_PREERASE)
Global Const $CDDS_ITEMPREPAINT = BitOR($CDDS_ITEM, $CDDS_PREPAINT)

Global Const $CDIS_CHECKED = 0x8
Global Const $CDIS_DEFAULT = 0x20
Global Const $CDIS_DISABLED = 0x4
Global Const $CDIS_FOCUS = 0x10
Global Const $CDIS_GRAYED = 0x2
Global Const $CDIS_HOT = 0x40
Global Const $CDIS_INDETERMINATE = 0x100
Global Const $CDIS_MARKED = 0x80
Global Const $CDIS_SELECTED = 0x1
Global Const $CDIS_SHOWKEYBOARDCUES = 0x200

Global Const $CDRF_DODEFAULT = 0x0
Global Const $CDRF_NEWFONT = 0x2
Global Const $CDRF_NOTIFYITEMDRAW = 0x20
Global Const $CDRF_NOTIFYPOSTERASE = 0x40
Global Const $CDRF_NOTIFYPOSTPAINT = 0x10
Global Const $CDRF_NOTIFYSUBITEMDRAW = 0x20
Global Const $CDRF_SKIPDEFAULT = 0x4
#ce
;fonts for custom draw example
;bold
Global $aFont1 = DLLCall("gdi32.dll","int","CreateFont", "int", 14, "int", 0, "int", 0, "int", 0, "int", 700, _
                        "dword", 0, "dword", 0, "dword", 0, "dword", 0, "dword", 0, "dword", 0, "dword", 0, _
                        "dword", 0, "str", "")
;italic
Global $aFont2 = DLLCall("gdi32.dll","int","CreateFont", "int", 14, "int", 0, "int", 0, "int", 0, "int", 400, _
                        "dword", 1, "dword", 0, "dword", 0, "dword", 0, "dword", 0, "dword", 0, "dword", 0, _
                        "dword", 0, "str", "")



$GUI = GUICreate("Listview Custom Draw", 400, 300)

$cListView = GUICtrlCreateListView("", 2, 2, 394, 268, -1, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))
$hListView = GUICtrlGetHandle($cListView)

_GUICtrlListView_InsertColumn($hListView, 0, "Column 1", 100)
_GUICtrlListView_InsertColumn($hListView, 1, "Column 2", 100)
_GUICtrlListView_InsertColumn($hListView, 2, "Column 3", 100)

; Add items
For $i = 1 To 30
    _GUICtrlListView_AddItem($hListView, "Row" & $i & ": Col 1", $i-1)
    For $j = 1 To 2
        _GUICtrlListView_AddSubItem ($hListView, $i-1, "Row" & $i & ": Col " & $j+1, $j)
    Next
Next

GUICtrlCreateInput("", 50, 275, 100, 15)

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

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE
DLLCall("gdi32.dll","int","DeleteObject", "hwnd", $aFont1[0])
DLLCall("gdi32.dll","int","DeleteObject", "hwnd", $aFont2[0])
Exit

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
                    If Not _GUICtrlListView_GetViewDetails($hWndFrom) Then Return $GUI_RUNDEFMSG
                    Local $tCustDraw = DllStructCreate('hwnd hwndFrom;int idFrom;int code;' & _
                                        'dword DrawStage;hwnd hdc;long rect[4];dword ItemSpec;int ItemState;dword Itemlparam;' & _
                                        'dword clrText;dword clrTextBk;int SubItem;' & _
                                        'dword ItemType;dword clrFace;int IconEffect;int IconPhase;int PartID;int StateID;long rectText[4];int Align', _ ;winxp or later
                                        $lParam), $iDrawStage, $iItem, $iSubitem, $hDC, $tRect, $iColor1, $iColor2, $iColor3
                    $iDrawStage = DllStructGetData($tCustDraw, 'DrawStage')
                    Switch $iDrawStage
                        Case $CDDS_PREPAINT
                            Return $CDRF_NOTIFYITEMDRAW
                        Case $CDDS_ITEMPREPAINT
                            Return $CDRF_NOTIFYSUBITEMDRAW
                        Case $CDDS_ITEMPOSTPAINT
                        Case BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM)
                            $iItem = DllStructGetData($tCustDraw, 'ItemSpec')
                            $iSubitem = DllStructGetData($tCustDraw, 'SubItem')
                            If _GUICtrlListView_GetItemSelected($hWndFrom, $iItem) Then
                                $hDC = _WinAPI_GetDC($hWndFrom)
                                $tRect = DllStructCreate('long;long;long;long')
                                If $iSubitem = 0 Then
                                    DllCall('user32.dll','int','SendMessage', 'hwnd',$hWndFrom, 'uint',$LVM_GETSUBITEMRECT, 'wparam',$iItem, 'lparam',DllStructGetPtr($tRect))
                                    DllStructSetData($tRect, 1, 2)
                                    DllCall('user32.dll', 'int', 'FillRect', 'ptr', $hDC, 'ptr', DllStructGetPtr($tRect), 'int', _WinAPI_GetStockObject(4))
                                EndIf
                                DllStructSetData($tRect, 1, 2)
                                DllStructSetData($tRect, 2, $iSubitem)
                                DllCall('user32.dll','int','SendMessage', 'hwnd',$hWndFrom, 'uint',$LVM_GETSUBITEMRECT, 'wparam',$iItem, 'lparam',DllStructGetPtr($tRect))
                                Local $sText = _GUICtrlListView_GetItemText($hWndFrom, $iItem, $iSubitem)
                                DLLCall("gdi32.dll","int","SetTextColor", "ptr", $hDC, "int", RGB2BGR(0xffff00))
                                DLLCall("gdi32.dll","int","SetBkMode", "ptr", $hDC, "int", 1)
                                DllStructSetData($tRect, 1, DllStructGetData($tRect, 1)+2)
                                _WinAPI_DrawText($hDC, $sText, $tRect, 0x8000) ;; $DT_END_ELLIPSIS
                                _WinAPI_ReleaseDC($hWndFrom, $hDC)
                                Return $CDRF_SKIPDEFAULT
                            EndIf
                            Switch $iItem
                                Case 0 To 9 ;for rows 1-10 lets do this
                                    $iColor1 = RGB2BGR(0xFBFFD8)
                                    $iColor2 = RGB2BGR(-1)
                                    $iColor3 = RGB2BGR(0xFF0000)
                                    If Mod($iSubitem, 2) Then ;odd columns
                                        DllStructSetData($tCustDraw, 'clrTextBk', $iColor1)
                                        DllStructSetData($tCustDraw, 'clrText', 0)
                                    Else ;even columns
                                        DllStructSetData($tCustDraw, 'clrTextBk', $iColor2)
                                        DllStructSetData($tCustDraw, 'clrText', $iColor3)
                                    EndIf
                                Case 10 To 19 ;for rows 11-20 lets do this
                                    $iColor1 = RGB2BGR(0xFBFFD8)
                                    $iColor2 = RGB2BGR(0x3DF8FF)
                                    $hDC = DllStructGetData($tCustDraw, 'hdc')
                                    If Mod($iItem, 2) Then
                                        If Mod($iSubitem, 2) Then
                                            DllStructSetData($tCustDraw, 'clrTextBk', $iColor1)
                                        Else
                                            DllStructSetData($tCustDraw, 'clrTextBk', $iColor2)
                                        EndIf
                                        DLLCall("gdi32.dll","hwnd","SelectObject", "hwnd", $hDC, "hwnd", $aFont1[0]) ;select our chosen font into DC
                                    Else
                                        If Mod($iSubitem, 2) Then
                                            DllStructSetData($tCustDraw, 'clrTextBk', $iColor2)
                                        Else
                                            DllStructSetData($tCustDraw, 'clrTextBk', $iColor1)
                                        EndIf
                                        DLLCall("gdi32.dll","hwnd","SelectObject", "hwnd", $hDC, "hwnd", $aFont2[0])
                                    EndIf
                                Case 20 To 29 ;for rows 21-30 lets do this
                                    $iColor1 = RGB2BGR(0xFBFFD8)
                                    $iColor2 = RGB2BGR(-1)
                                    If Mod($iItem, 2) Then ;odd rows
                                        DllStructSetData($tCustDraw, 'clrTextBk', $iColor2)
                                    Else
                                        DllStructSetData($tCustDraw, 'clrTextBk', $iColor1)
                                    EndIf
                            EndSwitch
                            Return $CDRF_NEWFONT
                        Case BitOR($CDDS_ITEMPOSTPAINT, $CDDS_SUBITEM)
                        Case Else
                    EndSwitch
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func RGB2BGR($iColor)
    Return BitAND(BitShift(String(Binary($iColor)), 8), 0xFFFFFF)
EndFunc

Source:

 

Link to comment
Share on other sites

Problem: Replace

If _GUICtrlListView_GetItemSelected($hWndFrom, $iItem) Then

with

If _GUICtrlListView_GetItemSelected($hWndFrom, $iItem) Or _GUICtrlListView_GetItemFocused($hWndFrom, $iItem) Then

 

Also: Look at _GUICtrlListView_RedrawItems

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...