LV_SetSelColors() - user-defined selection colors for ListViews

Post your working scripts, libraries and tools for AHK v1.1 and older
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

LV_SetSelColors() - user-defined selection colors for ListViews

Post by just me » 01 May 2016, 15:50

For a long time I was wondering why selected ListView rows ignore colors set when processing NM_CUSTOMDRAW notifications. Now I seemingly found the reason: The CDIS_SELECTED state in the uItemState field of NMCUSTOMDRAW must be removed.

The function:

Code: Select all

; ==================================================================================================================================
; Sets the colors for selected rows in a ListView.
; Parameters:
;     HLV      -  handle (HWND) of the ListView control.
;     BkgClr   -  background color as RGB integer value (0xRRGGBB).
;                 If omitted or empty the ListViews's background color will be used.
;     TxtClr   -  text color as RGB integer value (0xRRGGBB).
;                 If omitted or empty the ListView's text color will be used.
;                 If both BkgColor and TxtColor are omitted or empty the control will be reset to use the default colors.
;     Dummy    -  must be omitted or empty!!!
; Return value:
;     No return value.
; Remarks:
;     The function adds a handler for WM_NOTIFY messages to the chain of existing handlers.
; ==================================================================================================================================
LV_SetSelColors(HLV, BkgClr := "", TxtClr := "", Dummy := "") {
   Static OffCode := A_PtrSize * 2              ; offset of code        (NMHDR)
        , OffStage := A_PtrSize * 3             ; offset of dwDrawStage (NMCUSTOMDRAW)
        , OffItem := (A_PtrSize * 5) + 16       ; offset of dwItemSpec  (NMCUSTOMDRAW)
        , OffItemState := OffItem + A_PtrSize   ; offset of uItemState  (NMCUSTOMDRAW)
        , OffClrText := (A_PtrSize * 8) + 16    ; offset of clrText     (NMLVCUSTOMDRAW)
        , OffClrTextBk := OffClrText + 4        ; offset of clrTextBk   (NMLVCUSTOMDRAW)
        , Controls := {}
        , MsgFunc := Func("LV_SetSelColors")
        , IsActive := False
   Local Item, H, LV, Stage
   If (Dummy = "") { ; user call ------------------------------------------------------------------------------------------------------
      If (BkgClr = "") && (TxtClr = "")
         Controls.Delete(HLV)
      Else {
         If (BkgClr <> "")
            Controls[HLV, "B"] := ((BkgClr & 0xFF0000) >> 16) | (BkgClr & 0x00FF00) | ((BkgClr & 0x0000FF) << 16) ; RGB -> BGR
         If (TxtClr <> "")
            Controls[HLV, "T"] := ((TxtClr & 0xFF0000) >> 16) | (TxtClr & 0x00FF00) | ((TxtClr & 0x0000FF) << 16) ; RGB -> BGR
      }
      If (Controls.MaxIndex() = "") {
         If (IsActive) {
            OnMessage(0x004E, MsgFunc, 0)
            IsActive := False
      }  }
      Else If !(IsActive) {
         OnMessage(0x004E, MsgFunc)
         IsActive := True
   }  }
   Else { ; system call ------------------------------------------------------------------------------------------------------------
      ; HLV : wParam, BkgClr : lParam, TxtClr : uMsg, Dummy : hWnd
      H := NumGet(BkgClr + 0, "UPtr")
      If (LV := Controls[H]) && (NumGet(BkgClr + OffCode, "Int") = -12) { ; NM_CUSTOMDRAW
         Stage := NumGet(BkgClr + OffStage, "UInt")
         If (Stage = 0x00010001) { ; CDDS_ITEMPREPAINT
            Item := NumGet(BkgClr + OffItem, "UPtr")
            If DllCall("SendMessage", "Ptr", H, "UInt", 0x102C, "Ptr", Item, "Ptr", 0x0002, "UInt") { ; LVM_GETITEMSTATE, LVIS_SELECTED
               ; The trick: remove the CDIS_SELECTED (0x0001) and CDIS_FOCUS (0x0010) states from uItemState and set the colors.
               NumPut(NumGet(BkgClr + OffItemState, "UInt") & ~0x0011, BkgClr + OffItemState, "UInt")
               If (LV.B <> "")
                  NumPut(LV.B, BkgClr + OffClrTextBk, "UInt")
               If (LV.T <> "")
                  NumPut(LV.T, BkgClr + OffClrText, "UInt")
               Return 0x02 ; CDRF_NEWFONT
         }  }
         Else If (Stage = 0x00000001) ; CDDS_PREPAINT
            Return 0x20 ; CDRF_NOTIFYITEMDRAW
         Return 0x00 ; CDRF_DODEFAULT
}  }  }
A sample script:

Code: Select all

#NoEnv
SetBatchLines, -1
Gui, Margin, 20, 20
Gui, Add, ListView, w600 r20 hwndHLV, Column 1|Column 2|Column 3|Column 4
Loop, 20
   LV_Add("", A_Index, A_Index, A_Index, A_Index)
LV_SetSelColors(HLV, 0xD9EBF9)
Gui, Add, Button, gGetSelected, Get Selected Item
Gui, Show, , ListView with user-defined selection colors
Return
GuiClose:
ExitApp
GetSelected:
Gui, +OwnDialogs
MsgBox, 0, Selected Item, % LV_GetNext()
Return
The script is working on Win 10. Please tell me whether it is working on previous versions too.
Edit: So it seems to be working on Windows versions prior 10, too. Thanks to all testers.


Important: The function depends on processing WM_NOTIFY (0x004E) -> NM_CUSTOMDRAW (-12) notifications for the ListView controls. If you need to process this notifications for other purposes you cannot use it.
Last edited by just me on 04 May 2016, 10:12, edited 1 time in total.

Guest88

Re: [POC] LV_SetSelColors()

Post by Guest88 » 01 May 2016, 18:43

It seems not working on Windows XP SP3.

tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: [POC] LV_SetSelColors()

Post by tmplinshi » 01 May 2016, 20:08

Nice

garry
Posts: 3740
Joined: 22 Dec 2013, 12:50

Re: [POC] LV_SetSelColors()

Post by garry » 02 May 2016, 02:35

@just me
it works for me with Windows XP Home SP3

Guest

Re: [POC] LV_SetSelColors()

Post by Guest » 02 May 2016, 04:43

Works on Win7 x64
Very nice!

User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: [POC] LV_SetSelColors()

Post by kczx3 » 02 May 2016, 15:09

Works for me on Win7 x64 but it is now blocking my LV_Colors from working.

Additionally, would this solution also be similar to getting the LVS_EX_BORDERSELECT style to function properly? I never have been able to get that to work.

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [POC] LV_SetSelColors()

Post by just me » 03 May 2016, 01:52

kczx3, the two cannot work simultaneously. Both are processing and responding NM_CUSTOMDRAW notifications. So only the first called message handler will work. I'll add the function to LV_Colors if required.

User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: [POC] LV_SetSelColors()

Post by kczx3 » 04 May 2016, 07:51

Define required? I think it'd be an awesome addition to LV_Colors if you feel so inclined to add it. I think that is beyond this post though since it's really just for Proof of Concept, which you obviously have done. Great work as usual.

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [POC] LV_SetSelColors()

Post by just me » 04 May 2016, 09:46

Hello kczx3, it has been already reqired by 'just me'. ;)

carno
Posts: 265
Joined: 20 Jun 2014, 16:48

Re: LV_SetSelColors() - user-defined selection colors for ListViews

Post by carno » 06 May 2016, 08:13

It is beautiful. Thanks!

m3user
Posts: 235
Joined: 17 Jan 2014, 18:11

Re: LV_SetSelColors() - user-defined selection colors for ListViews

Post by m3user » 11 Apr 2020, 04:11

I was searching for the solution to change the color of the selected row in ListView and I think this is the best and simplest function.
Is there a similar way to change the font color?

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: LV_SetSelColors() - user-defined selection colors for ListViews

Post by just me » 11 Apr 2020, 06:16

The font color of what?

garry
Posts: 3740
Joined: 22 Dec 2013, 12:50

Re: LV_SetSelColors() - user-defined selection colors for ListViews

Post by garry » 11 Apr 2020, 06:45

LV example from just me , added : change font color from LV after 2 seconds , but just all , not desired columns / rows

Code: Select all

;-- Listview from justme
;-------- saved at Freitag, 10. April 2020 17:34:50 --------------
;- A problem with list view LV_GetCount 
;- https://www.autohotkey.com/boards/viewtopic.php?f=76&t=74476

#SingleInstance, Force
#Persistent
Gui,1:Font,s12 cBlack,Lucida Console
SetWorkingDir, % A_ScriptDir
Gui, Add, ListView, r20 w700 gMyListView vLV1, Name|Path
Gui, Add, Button,, % "Start selected"
Scripts := ["C:\foo.ahk"
          , "C:\bar.ahk"
          , "C:\baz.ahk"]
for Index, ScriptFullPath in Scripts {
    SplitPath, ScriptFullPath, ScriptName
    LV_Add("", ScriptName, ScriptFullPath)
}
LV_ModifyCol()
Gui, Show
sleep,2000
gosub,a1
return
Guiclose:
exitapp

MyListView:
    if (A_GuiEvent = "DoubleClick") {
        LV_GetText(RowText, A_EventInfo) ; Get the text from the row's first field.
        MsgBox, % A_EventInfo "`n" RowText
    }
return

ButtonStartSelected:
   If LV_GetCount("Selected")
   {
      SelectedRow := 0
      While (SelectedRow := LV_GetNext(SelectedRow))
      {
         LV_GetText(RetrievedText, SelectedRow, 2)
         MsgBox, % A_AhkPath A_Space """" RetrievedText """"
      }
   }
Return
esc::exitapp

a1:
GUI,1:Font,s12 cRed ,Lucida Console
Guicontrol,1:font,LV1
return

m3user
Posts: 235
Joined: 17 Jan 2014, 18:11

Re: LV_SetSelColors() - user-defined selection colors for ListViews

Post by m3user » 11 Apr 2020, 17:52

just me wrote:
11 Apr 2020, 06:16
The font color of what?
Sorry, I mean the font color of the selected row.

neogna2
Posts: 586
Joined: 15 Sep 2016, 15:44

Re: LV_SetSelColors() - user-defined selection colors for ListViews

Post by neogna2 » 12 Apr 2020, 04:23

m3user wrote:
11 Apr 2020, 17:52
Sorry, I mean the font color of the selected row.
You can change text color and/or background color for selected cells with just_me's LV_Colors class, see the SelectionColors() method in that class.

@just_me: is there any performance difference or any other notable difference between using this function to change selection background color compared to using your LV_Colors class?

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: LV_SetSelColors() - user-defined selection colors for ListViews

Post by just me » 12 Apr 2020, 04:59

@m3user,
m3user wrote:Sorry, I mean the font color of the selected row.
The 3rd function parameter i called TxtClr. Doesn't it work any more?

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: LV_SetSelColors() - user-defined selection colors for ListViews

Post by just me » 12 Apr 2020, 05:21

@neogna2,
at least if you only use selection colors, I don't think there will be a 'notable difference'.

m3user
Posts: 235
Joined: 17 Jan 2014, 18:11

Re: LV_SetSelColors() - user-defined selection colors for ListViews

Post by m3user » 12 Apr 2020, 10:59

just me wrote:
12 Apr 2020, 04:59
The 3rd function parameter i called TxtClr. Doesn't it work any more?
It works, of course. Thanks and sorry for the confusion. :oops:

m3user
Posts: 235
Joined: 17 Jan 2014, 18:11

Re: LV_SetSelColors() - user-defined selection colors for ListViews

Post by m3user » 03 Mar 2021, 16:01

After a while I noticed that if I scroll up/down very quickly, the ListView would eventually freeze/get empty - even with the sample script.
Is there any way to avoid this? Thanks.

User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: LV_SetSelColors() - user-defined selection colors for ListViews

Post by kczx3 » 03 Mar 2021, 20:34

m3user wrote:
03 Mar 2021, 16:01
After a while I noticed that if I scroll up/down very quickly, the ListView would eventually freeze/get empty - even with the sample script.
Is there any way to avoid this? Thanks.
Your only hope is to add something like Critical, 100 to the function however that is not guaranteed to work either.

Post Reply

Return to “Scripts and Functions (v1)”