Jump to content
DavidStark

ListView CustomDraw highlighted row that stays when no selection is made

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:

 

Share this post


Link to post
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

  • Similar Content

    • By Slipk
      Hello everybody,
      #include <GUIConstantsEx.au3> #include <ListViewConstants.au3> #include <WindowsConstants.au3> #include <GUIListViewEx.au3> $Form1 = GUICreate("Form1", 539, 350, 192, 124) $ListView1 = GUICtrlCreateListView("CLM1|CLM2", 0, 0, 538, 326) GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 0, 150) GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 1, 150) Local $dynamic = GUICtrlCreateListViewItem("Example1|Example2", $ListView1) $SubMenu = GUICtrlCreateContextMenu($dynamic) $Run = GUICtrlCreateMenuItem("Run", $SubMenu) $Edit = GUICtrlCreateMenuItem("Edit", $SubMenu) $Delete = GUICtrlCreateMenuItem("Delete", $SubMenu) Local $dynamic2 = GUICtrlCreateListViewItem("Example3|Example6", $ListView1) $SubMenu = GUICtrlCreateContextMenu($dynamic2) $Run = GUICtrlCreateMenuItem("Run", $SubMenu) $Edit = GUICtrlCreateMenuItem("Edit", $SubMenu) $Delete = GUICtrlCreateMenuItem("Delete", $SubMenu) _GUIListViewEx_Init($ListView1, "", 0, 0, True, 64) _GUIListViewEx_MsgRegister() GUISetState(@SW_SHOW) While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit EndSwitch WEnd I use GUIListViewEx.au3 for position of items in listview but when I move one the context menu disappear. Any solution of this?
      Any method than array it is possible?
      Thank you, appreciate it.
       
       
    • By Slipk
      Hello everybody,
      I download the GUIListViewEx.au3 by Melba23 in order to move up or down my items from a listview.
      Everything it's looking good in script but when I move an item it will crash.
      Any suggestions?
      Thank you! 

    • By Slipk
      Hello everybody,
      Sorry for my bad english.
       
      I try to figure out if I have a dynamic listview with as many items as I want, how to save to a text file all the data listview contains in the same form that you put when you create a listviewitem. I will give you an example.
      When the script is running it will show you the listview and some items. How to take the items data "Data1|Data1_Sub1|Data1_Sub2" in this format and paste into a text file? All of them.
      I tried to explain as good as I can.
      Thank you for your attention!
      #include <GUIConstantsEx.au3> #include <ListViewConstants.au3> #include <WindowsConstants.au3> $Form_Menu = GUICreate("Form Example", 351, 234, -1, -1) $Form_Menu_ListView1 = GUICtrlCreateListView("Column #1|Column #2|Column #3", 0, 0, 346, 230) GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 0, 75) GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 1, 75) GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 2, 75) GUICtrlCreateListViewItem("Data1|Data1_Sub1|Data1_Sub2", $Form_Menu_ListView1) GUICtrlCreateListViewItem("Data2|Data2_Sub1|Data2_Sub2", $Form_Menu_ListView1) GUICtrlCreateListViewItem("DataN|DataN_SubN|DataN_SubN", $Form_Menu_ListView1) ;The data that appear in the listview be saved in a file like that : #cs Data1|Data1_Sub1|Data1_Sub2 Data2|Data2_Sub1|Data2_Sub2 DataN|DataN_SubN|DataN_SubN #ce GUISetState(@SW_SHOW, $Form_Menu) While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit EndSwitch WEnd
    • By Slipk
      Hello,
      I tried with many methods and searched a lot for items to move up and down but couldn't find it.
      Sorry for my bad english.
      #include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <ListViewConstants.au3> #include <WindowsConstants.au3> #include <GuiListView.au3> #Region ### START Koda GUI section ### Form= $Form1 = GUICreate("Form1", 307, 247, 192, 124) GUISetFont(10, 400, 0, "Arial") $ListView1 = GUICtrlCreateListView("C1|C2|C3", 0, 0, 250, 246) GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 0, 50) GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 1, 60) GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 2, 100) GUICtrlCreateListViewItem("Test1|Test2|Test3", $ListView1) GUICtrlCreateListViewItem("Cat|Dog|Fish", $ListView1) GUICtrlCreateListViewItem("ABC|DEF|GHI", $ListView1) $Button1 = GUICtrlCreateButton("/\", 264, 8, 27, 25) GUICtrlSetFont(-1, 10, 800, 0, "Arial") $Button2 = GUICtrlCreateButton("\/", 264, 40, 27, 25) GUICtrlSetFont(-1, 10, 800, 0, "Arial") GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1     $nMsg = GUIGetMsg()     Switch $nMsg         Case $GUI_EVENT_CLOSE             Exit         Case $Button1 ;up         Case $Button2 ;down     EndSwitch WEnd  
      Thank you for your help!
    • By Broihon
      Hey guys,

      I ran into a problem when I wanted to delete items of a listview using the delete key. My approach is to register my own WndProc for the listview and then filter the $WM_GETDLGCODE msg and then call the original WndProc.
      That works like a charm. The problem is that when the listview gets redrawn it somehow ends up in an infinite loop. The listview is suddenly emtpy and I can't interact with any controls of the GUI at all. Here's the code:
       
      #include <GUIConstantsEx.au3> #include <GUIListView.au3> #include <WinAPI.au3> $h_GUI = GUICreate("Test", 200, 200, 350, 350) $h_LV = GUICtrlCreateListView("Col 1|Col 2|Col 3", 0, 0, 200, 200) _GUICtrlListView_AddItem($h_LV, "") _GUICtrlListView_AddSubItem($h_LV, 0, "bla0", 0) _GUICtrlListView_AddSubItem($h_LV, 0, "bla0", 1) _GUICtrlListView_AddSubItem($h_LV, 0, "bla0", 2) _GUICtrlListView_AddItem($h_LV, "") _GUICtrlListView_AddSubItem($h_LV, 1, "bla1", 0) _GUICtrlListView_AddSubItem($h_LV, 1, "bla1", 1) _GUICtrlListView_AddSubItem($h_LV, 1, "bla1", 2) _GUICtrlListView_AddItem($h_LV, "") _GUICtrlListView_AddSubItem($h_LV, 2, "bla2", 0) _GUICtrlListView_AddSubItem($h_LV, 2, "bla2", 1) _GUICtrlListView_AddSubItem($h_LV, 2, "bla2", 2) _GUICtrlListView_AddItem($h_LV, "") _GUICtrlListView_AddSubItem($h_LV, 3, "bla3", 0) _GUICtrlListView_AddSubItem($h_LV, 3, "bla3", 1) _GUICtrlListView_AddSubItem($h_LV, 3, "bla3", 2) $h_LV_NewWndProc = DllCallbackRegister("WndProc_LV", "int", "hwnd;uint;wparam;lparam") $g_LV_OldWndProc = _WinAPI_SetWindowLong(GUICtrlGetHandle($h_LV), $GWL_WNDPROC, DllCallbackGetPtr($h_LV_NewWndProc)) GUISetState(@SW_SHOW) Func WndProc_LV($hWnd, $uMsg, $wParam, $lParam) Return _WinAPI_CallWindowProc($g_LV_OldWndProc, $hWnd, $uMsg, $wParam, $lParam) EndFunc ;==>WndProc_GUI Do Until GUIGetMsg() = $GUI_EVENT_CLOSE DllCallbackFree($h_LV_NewWndProc) As you can see I'm doing nothing in the WndProc of the listview. I'm simply calling the original WndProc. This still "freezes" when I mess with the width of the columns or in the original project when I add more items that they don't fit in the listview and I have to scroll. If I don't do that it's working fine.
×
×
  • Create New...