DavidStark

ListView CustomDraw highlighted row that stays when no selection is made

3 posts in this topic

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

    • Monica
      By Monica
      Hi guys!! I'm going crazy... please help me -.-
      First, open the attached screenshot. Second: I'd like to grab info from external window. The program is "Metatrader4", a tool for trading and charts analysis.
      The function _GUICtrlListView_GetItemText() return an empty string! I tried to change the index $index (the second parameter) into Number($index), as recommended by other similar posts in this forum, but this did not solve my problem 
      Well, why I'm going mad? Because in my mind an UDF approach works great or it does not work at all; instead, in my code something works and something else does not. I really don't understand why... and you?
      THXX!!!!  
      $handle=ControlGetHandle("Expert - "&$expertname,"",1383);List: Variable|Value For $i=0 To _GUICtrlListView_GetItemCount($handle)-1;WORKS!!! $temp=_GUICtrlListView_GetItemText($handle,0+$i);RETURN EMPTY STRING :-( MsgBox(0, "", $temp) $temp = _GUICtrlListView_GetItemSelected($handle,$i);WORKS!!! MsgBox(0, "", $temp) Next  

    • mLipok
      By mLipok
      I was not lucky to find the right function so I created it by my self:
      _GUICtrlListView_GetColumnID_ByName()
      Example:
       
      #include <GUIConstantsEx.au3> #include <GuiListView.au3> #include <MsgBoxConstants.au3> Example() Func Example() GUICreate("ListView Get Column ID", 400, 300) Local $idListview = GUICtrlCreateListView("Alfa|Beta|Gama", 2, 2, 394, 268) GUISetState(@SW_SHOW) _GUICtrlListView_SetColumnOrder($idListview, "2|0|1") MsgBox($MB_SYSTEMMODAL, "Information", "Column ID: " & _GUICtrlListView_GetColumnID_ByName($idListview, 'Gama')) ; Loop until the user exits. Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete() EndFunc ;==>Example Func _GUICtrlListView_GetColumnID_ByName($hListView, $sColumnToFind) Local $iColumn_Count = _GUICtrlListView_GetColumnCount($hListView) Local $aColumns For $iColumn_idx = 0 To $iColumn_Count - 1 $aColumns = _GUICtrlListView_GetColumn($hListView, $iColumn_idx) If $aColumns[5] = $sColumnToFind Then Return $iColumn_idx EndIf Next Return SetError(1, 0, -1) EndFunc ;==>_GUICtrlListView_GetColumnID_ByName  
    • UEZ
      By UEZ
      Here a small tool I wrote to update my Sysinternal tools collection without the need to download always the whole package or visiting the site to check for updates. I know that there are several tools available (also some tools written in AutoIt) but here another one for the collection. It was good exercise for me to code it.
       
       
        
       
       
      Some files from cannot be downloaded although they are visible on the web site!
       
      Here the download link of the source code only: AutoIt Sysinternal Tools Synchronizer v0.99.1 build 2017-10-23 beta.7z  (1353 downloads previously)
      -=> Requires AutoIt version 3.3.13.20 or higher / tested on Win8.1 real machine and some VMs: Win7 / Vista / Win10
       
      Compiled exe only: @MediaFire
       
      Just select the Sysinternal Tools folder or create one and press the synchronize button to download the selected items. Click on AutoIt label (near to left upper corner) to open menu.
       
      Special thanks to LarsJ, Melba23 and mesale0077 for their help. 
       
      I've still some ideas to implement which are more gimmick related, so it is not finished yet...
      If you want to add your language please check out #Region Language. Thanks. 
       
      Please report any bug or if you have any suggestions.
       
      The language of the tool tip from each of the executable in the left list view were automatically created using Google translator and weren't checked for correctness.
       
      Br,
      UEZ
    • 0Ethan0
      By 0Ethan0
      Ahoy Autoit Community!
      After many trials and errors I am unable to solve a problem I am facing and would appreciate any kind of input or better yet a solution 
      The Premise: An embeded slideshow viewer that runs after double-clicking an item in a ListView (each item will generate a different slideshow images).
      The Setup: GUI with a ListView Control and a simple exit button.
      The Issue: Once double clicked the slide plays however the GUI "locks"/non responsive until the slide is over. Same thing if I click on the "Test" button.
      The Culprit: I believe since it's in the images loop it can't accept any other commands until that loop is over.
      The Wish: I want to be able to use the GUI functions (selecting other items, clicking on button etc.) while the slideshow plays.
      The Code (stripped and simplified as much as I could):
      #include <GuiListView.au3> #include <File.au3> #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> Opt("GUIOnEventMode", 1) HotKeySet("{Esc}", "_Exit") Global $c=0 Global $ssGDI[3], $ssGraphic[2], $ssImage Global Const $bg_color = "000000" Global Const $ssW = 480, $ssH = 320 Global $aFiles = _FileListToArrayRec("d:\testStage\", "*.jpg;*.png;*.bmp;*.gif;*.JPG;*.PNG;*.BMP;*.GIF", $FLTAR_FILES, $FLTAR_NORECUR ,$FLTAR_SORT ,$FLTAR_FULLPATH ) $guiW = 1200 $guiH = 726 $mainWindow = GUICreate("Slideshow Viewer", $guiW, $guiH, -1, -1, $WS_POPUP) $Button1 = GUICtrlCreateButton("Exit", 0, 0, 50, 50) GUICtrlSetOnEvent($Button1, "_Exit") $Button1 = GUICtrlCreateButton("Test", 60, 0, 50, 50) GUICtrlSetOnEvent($Button1, "Test") Global $ListView = GUICtrlCreateListView("Entry Name|Category", 5, 75, 195, 280) _GUICtrlListView_SetColumnWidth ($ListView, 0, 100) _GUICtrlListView_SetColumnWidth ($ListView, 1, 100) GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES) GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_FULLROWSELECT, $LVS_EX_FULLROWSELECT) GUICtrlCreateListViewItem("Name 1|Category 1", $ListView) GUICtrlCreateListViewItem("Name 2|Category 2", $ListView) screenshotWidgetInit($ssW,$ssH, 690, 100) GUISetState(@SW_SHOW, $mainWindow) GUIRegisterMsg($WM_NOTIFY, "WM_Notify_Events") While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE _Exit() EndSwitch WEnd Func Test() For $k = 1 To UBound($aFiles) - 1 screenshotWidgetTransition($aFiles[$k]) Next EndFunc Func ListView_Click() ConsoleWrite("Left Click") EndFunc Func ListView_DoubleClick() ConsoleWrite("Double Left Click") Test() EndFunc Func WM_Notify_Events($hWndGUI, $MsgID, $wParam, $lParam) #forceref $hWndGUI, $MsgID, $wParam Local $tagNMHDR, $event, $hwndFrom, $code $tagNMHDR = DllStructCreate("int;int;int", $lParam) If @error Then Return $event = DllStructGetData($tagNMHDR, 3) Select Case $wParam = $ListView Select Case $event = $NM_CLICK ListView_Click () Case $event = $NM_DBLCLK ListView_DoubleClick () EndSelect EndSelect Return $GUI_RUNDEFMSG EndFunc Func screenshotWidgetTransition($image, $delay = 0, $speed = 1, $sleep = 2000) Local $a, $d = $c, $iX, $iY $ssImage = _GDIPlus_ImageLoadFromFile($image) $iX = _GDIPlus_ImageGetWidth($ssImage) $iY = _GDIPlus_ImageGetHeight($ssImage) $FDesktop=$ssH/$ssW $Fact =1 If $iX > $ssW And $FDesktop > ($iY/$iX) Then $Fact=$ssW/$iX ElseIf $iY > $ssH Then $Fact=$ssH/$iY EndIf $H1 = Round(($Fact * $iY),0) $W1 = Round(($Fact * $iX),0) _GDIPlus_GraphicsDrawImageRect($ssGraphic[$d], $ssImage,($ssW - $W1)/2, ($ssH - $H1) / 2,$W1,$H1) WinSetTrans($ssGDI[$d], "", 0) WinSetOnTop($ssGDI[$d], "", 1) For $a = 0 To 254 Step $speed WinSetTrans($ssGDI[$d], "", $a) Sleep($delay) Next WinSetTrans($ssGDI[$d], "", 254) WinSetOnTop($ssGDI[Not ($d)], "", 0) WinSetTrans($ssGDI[Not ($d)], "", 0) _GDIPlus_GraphicsClear($ssGraphic[Not ($d)]) $c = 1 - $d _GDIPlus_ImageDispose ($ssImage) ; very important to realease the pics Sleep($sleep) EndFunc ;==>screenshotWidgetTransition Func screenshotWidgetInit($ssW,$ssH,$ssX,$ssY) $ssGDI[2] = GUICreate("", $ssW, $ssH, $ssX, $ssY, $WS_POPUP, $WS_EX_MDICHILD, $mainWindow) $ssGDI[0] = GUICreate("", $ssW, $ssH, 3, 3, $WS_POPUP, $WS_EX_MDICHILD, $ssGDI[2]) $ssGDI[1] = GUICreate("", $ssW, $ssH, 3, 3, $WS_POPUP, $WS_EX_MDICHILD, $ssGDI[2]) ; GUISetBkColor("0x" & $bg_color, $ssGDI[2]) GUISetState(@SW_SHOW, $ssGDI[2]) GUISetState(@SW_SHOW, $ssGDI[0]) GUISetState(@SW_SHOW, $ssGDI[1]) WinSetTrans($ssGDI[0], "", 0) WinSetTrans($ssGDI[1], "", 0) _GDIPlus_Startup() $ssGraphic[0] = _GDIPlus_GraphicsCreateFromHWND($ssGDI[0]) $ssGraphic[1] = _GDIPlus_GraphicsCreateFromHWND($ssGDI[1]) _GDIPlus_GraphicsClear($ssGraphic[0], "0xFF" & $bg_color) _GDIPlus_GraphicsClear($ssGraphic[1], "0xFF" & $bg_color) EndFunc ;==>screenshotWidgetInit Func _Exit() _GDIPlus_ImageDispose($ssImage) _GDIPlus_GraphicsDispose($ssGraphic[0]) _GDIPlus_GraphicsDispose($ssGraphic[1]) GUIDelete($ssGDI[0]) GUIDelete($ssGDI[1]) GUIDelete($ssGDI[2]) _GDIPlus_Shutdown() Exit EndFunc ;==>_Exit I hope someone can shed light on this; perhaps a different approach is needed?
      Thank you in advance!
      P.S.
      The script is patched from different scripts of different users in the forum - thank you again users!
    • Daka
      By Daka
      I know there are listbox and listview, but now I have?
      here is the video of infowindow 
      I tried to read mouse selection like for listbox:
      $listWindow = "[CLASS:TFormResearchGR]" $topicsList = "[CLASS:TMWrapper; INSTANCE:255]" WinWait($listWindow, "", 60) $hdlWindow = WinGetHandle($listWindow) $hdlList = ControlGetHandle($hdlWindow, "", $topicsList) _GUICtrlListBox_ClickItem($hdlList, 0, "left") $countOfList = _GUICtrlListBox_GetCount($hdlList) ConsoleWrite("Count of list: " & $countOfList & @LF) count of list is not working.
      I realiezed that there are difference between listbox and listview, but this is something different.
      and till now I never saw that you can go inside with infotool and also get instances.
       
      so Im confused how to get the list number and the names of selection?