LVColouredItems




Option Explicit
'

' Custom Draw Message to intercept

'

Public Enum WinNotifications
NM_FIRST = -0& ' (0U- 0U) ' // generic to all controls
NM_LAST = -99& ' (0U- 99U)
NM_OUTOFMEMORY = (NM_FIRST - 1)
NM_CLICK = (NM_FIRST - 2)
NM_DBLCLK = (NM_FIRST - 3)
NM_RETURN = (NM_FIRST - 4)
NM_RCLICK = (NM_FIRST - 5)
NM_RDBLCLK = (NM_FIRST - 6)
NM_SETFOCUS = (NM_FIRST - 7)
NM_KILLFOCUS = (NM_FIRST - 8)
NM_CUSTOMDRAW = (NM_FIRST - 12)
NM_HOVER = (NM_FIRST - 13)
End Enum
'

' Win API Rect structure

'

Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
'

' Custom Draw Structures

'

' The NMHDR structure contains information about a notification message. The pointer

' to this structure is specified as the lParam member of the WM_NOTIFY message.

'

Private Type NMHDR
hwndFrom As Long ' Window handle of control sending message
idFrom As Long ' Identifier of control sending message
code As Long ' Specifies the notification code
End Type
Private Type NMCUSTOMDRAWINFO
hdr As NMHDR
dwDrawStage As Long
hdc As Long
rc As RECT
dwItemSpec As Long
iItemState As Long
lItemLParam As Long
End Type
Private Type NMLVCUSTOMDRAW
nmcmd As NMCUSTOMDRAWINFO
clrText As Long
clrTextBk As Long
iSubItem As Integer
End Type
'

' Notify Message

'

Private Const WM_NOTIFY& = &H4E
'

' Custom Draw Messages

'

Private Const CDDS_PREPAINT& = &H1
Private Const CDDS_POSTPAINT& = &H2
Private Const CDDS_PREERASE& = &H3
Private Const CDDS_POSTERASE& = &H4
Private Const CDDS_ITEM& = &H10000
Private Const CDDS_ITEMPREPAINT& = CDDS_ITEM Or CDDS_PREPAINT
Private Const CDDS_ITEMPOSTPAINT& = CDDS_ITEM Or CDDS_POSTPAINT
Private Const CDDS_ITEMPREERASE& = CDDS_ITEM Or CDDS_PREERASE
Private Const CDDS_ITEMPOSTERASE& = CDDS_ITEM Or CDDS_POSTERASE
Private Const CDDS_SUBITEM& = &H20000
Private Const CDRF_DODEFAULT& = &H0
Private Const CDRF_NEWFONT& = &H2
Private Const CDRF_SKIPDEFAULT& = &H4
Private Const CDRF_NOTIFYPOSTPAINT& = &H10
Private Const CDRF_NOTIFYITEMDRAW& = &H20
Private Const CDRF_NOTIFYSUBITEMDRAW = &H20 ' flags are the same, we can distinguish by context
Private Const CDRF_NOTIFYPOSTERASE& = &H40
Private Const CDRF_NOTIFYITEMERASE& = &H80
'

' Win API Declarations

'

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal dwLength As Long)
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Const WM_GETFONT = &H31
Private Sub Form_Load()
Dim li As ListItem
Dim lCount As Long
'

' Setup the listview with 1 column and 25 listitems

'

With ListView1.ListItems
ListView1.ColumnHeaders.Add 1, "Test", "Column 1"
For lCount = 1 To 25
Set li = .Add(lCount, "key" & lCount, "This Is Line " & lCount)
Next
End With
'

' Now subclass the form and watch for WM_NOTIFY messages coming from the listview

'

' I'm using the Softcircuits subclass control here, although you can use any other

' (they all work in pretty much the same way). You could also do any AddressOf processing

' if you so wish. I just use the SC control because it's a lot quicker (and you don't have

' to remember to un-subclass your window afterwards)

'

With Subclass1
.hwnd = Me.hwnd
.Messages(WM_NOTIFY) = True
End With
End Sub
'_________________________________________________________


Private Sub Subclass1_WndProc(Msg As Long, wParam As Long, lParam As Long, Result As Long)
Dim tMessage As NMHDR
Dim lCode As Long
Dim tLVRedrawMessage As NMLVCUSTOMDRAW
Select Case Msg
'

' Should only be WM_NOTIFY (that's all we've subclassed)

'

Case WM_NOTIFY
'

' Same as in C : tMessage = (NMHDR) lParam;

'

'

' The .code section of the NMHDR notify structure contains the submessage

'

CopyMemory tMessage, ByVal lParam, Len(tMessage)
lCode = tMessage.code
Select Case lCode
Case NM_CUSTOMDRAW
'

' Make sure it's our listview raising the Custom Redraw message

'

If tMessage.hwndFrom <> ListView1.hwnd Then
'

' It's not ! - Return default processing to windows

'

Result = Subclass1.CallWndProc(Msg, wParam, lParam)
Exit Sub
End If
'

' Copy the message into our local structure

'

CopyMemory tLVRedrawMessage, ByVal lParam, Len(tLVRedrawMessage)
'

' Now process the Custom Redraw Messages in Order :

'

' CDDS_PREPAINT is at the beginning of the paint cycle.

' You must return the property value to get Custom painting

' to work correctly. In this example, we're only looking for

' item specific painting - although theoretically, you should

' be able to paint just about anything on the control, from

' bitmap backgrounds to changing fonts etc.

'

' (Just don't ask me how to do it (yet)).

'

If tLVRedrawMessage.nmcmd.dwDrawStage = CDDS_PREPAINT Then
'

' Request a notification for each item being painted

'

Result = CDRF_NOTIFYITEMDRAW
Exit Sub
End If
'

' Because we returned CDRF_NOTIFYITEMDRAW in the above code, CDDS_ITEMPREPAINT is now sent

' when the control is ready to paint an Item

'

If tLVRedrawMessage.nmcmd.dwDrawStage = CDDS_ITEMPREPAINT Then
'

' The item's about to be repainted - Here's where you can trap to see which item is being

' painted and so set the color accordingly

'

' To see which item is about to be painted, check :

'

' if tLVRedrawMessage.nmcm.dwItemSpec = required listview item number Then

'

' To Change the text and background colours in a list view control,

' set the clrText and clrTextBk members of the NMLVCUSTOMDRAW structure to the

' required color. Most other controls rely on the SetTextColor and SetBkColor API

' calls on the passed in hdc

'

' In this code I'm setting every second listitem to be red

'

'

With tLVRedrawMessage
If .nmcmd.dwItemSpec / 2 = CInt(.nmcmd.dwItemSpec / 2) Then
.clrTextBk = vbWhite
.clrText = vbRed
'

' You must remember to copy back the changes made in tLVRedrawMessage to the LPARAM value

'

CopyMemory ByVal lParam, tLVRedrawMessage, Len(tLVRedrawMessage)
Exit Sub
Else
'

' This is standard painting stuff - let windows do it for us

'

Result = CDRF_DODEFAULT
Exit Sub
End If
End With
End If
Case Else
'

' Other messages from the listview which we're not interested in should be passed back

'

Result = Subclass1.CallWndProc(Msg, wParam, lParam)
Exit Sub
End Select
End Select
End Sub











( lvcoloureditems.html )- by Paolo Puglisi - Modifica del 17/12/2023