Rubrik: Controls · ListView | VB-Versionen: VB4, VB5, VB6 | 09.12.01 |
Hintergrundfarbe von ListItems-Einträgen ändern Ein Beispiel, wie man jede zweite Zeile eines ListView-Controls mit einer anderen Hintergrundfarbe versehen kann. | ||
Autor: Thomas Bannert | Bewertung: | Views: 27.853 |
ohne Homepage | System: Win9x, WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 | Beispielprojekt auf CD |
Das ListView-Control erfreut sich besonderer Beliebtheit bei den Programmieren, da es sehr flexible ist und sich auf diese Weise auch leicht mehrspaltige Listen erstellen lassen.
Gerade in der Report-Ansicht würden sich viele Entwickler wünschen, dass man die Hintergrundfarbe zur Darstellung der kompletten Zeile eines Eintrags individuell festlegen lassen kann. Auch nicht schlecht wäre die Möglichkeit für jeden zweiten Eintrag immer die selbe Hintergrundfarbe zu verwenden. Und genau diese Funktionalität zeigt Ihnen unser heutiger Tipp.
Hierzu muss man mal wieder tief in die API-Trickliste greifen
Vorab eins: WICHTIG !!!
Das was nachfolgend an Code kommt, ist mit größter Vorsicht zu genießen SubClassing ist ne super tolle Sache, kann aber auch super toll in die Hose gehen...
...also NIEMALS versuchen die Funktion WindowProc zu debuggen. Keine Haltepunkte oder Variablenüberwachung. Vor dem Testen immer speichern, vor dem Beenden immer die WindowProc wiederherstellen und NIEMALS versuchen die Funktion WindowProc zu debuggen!!! (Hab ich mich da etwa wiederholt
Mit diesem Code wird die ganze Sache gestartet.
Private Sub Form_Load() ' WindowProc umleiten (Subclassing) lCCHwnd = Me.ListView1.hwnd lWindowProcOld = SetWindowLong(hwnd, GWL_WNDPROC, _ AddressOf WindowProc) ' Hintergrundfarbe jeder zweiten Zeile glbLVWBackColor = &H00C0E0FF& ' Hier das ListView-Control mit Daten füllen ... End Sub Private Sub Form_Unload(Cancel As Integer) ' Sublassing beenden Call SetWindowLong(Me.hwnd, GWL_WNDPROC, lWindowProcOld) End Sub
Man kann das ganze natürlich auch in jeder anderen Funktion starten und beenden, aber bitte unbedingt an das Beenden denken!!!
Und hier ein bissel Code, der in ein neues Modul des Projekts gehört:
' modLSV_Color.bas Option Explicit ' WM_NOTIFY Public Enum WinNotifications NM_FIRST = (-0&) NM_LAST = (-99&) 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 Public Const WM_NOTIFY As Long = &H4E& ' CustomDraw Konstanten Public Const CDDS_PREPAINT As Long = &H1& Public Const CDRF_NOTIFYITEMDRAW As Long = &H20& Public Const CDDS_ITEM As Long = &H10000 Public Const CDDS_ITEMPREPAINT As Long = CDDS_ITEM Or _ CDDS_PREPAINT ' Notification Message Struktur ' Ist lParam einer WM_NOTIFY Message. Public Type NMHDR ' Fensterhandle des Controls, welches die Nachricht ' sendet hWndFrom As Long ' ID des Controls idFrom As Long ' Nachrichten-Code code As Long End Type ' RECHTECK siehe MSDN Public Type RECT Left As Long Top As Long Right As Long Bottom As Long End Type ' NM_CUSTOMDRAW Benachrichtigungs-Message Public Type NMCUSTOMDRAW hdr As NMHDR dwDrawStage As Long hDC As Long rc As RECT dwItemSpec As Long uItemState As Long lItemlParam As Long End Type ' NM_CUSTOMDRAW von einem ListView Public Type NMLVCUSTOMDRAW nmcd As NMCUSTOMDRAW clrText As Long clrTextBk As Long iSubItem As Integer ' NUR IE >= 4.0 End Type ' API Funktionen Public Declare Function CallWindowProc Lib "user32" _ Alias "CallWindowProcA" ( _ ByVal lpPrevWndFunc As Long, _ ByVal hwnd As Long, _ ByVal Msg As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long Public Declare Sub CopyMemory Lib "kernel32" _ Alias "RtlMoveMemory" ( _ lpDest As Any, _ lpSource As Any, _ ByVal cBytes&) Public Declare Function SetWindowLong Lib "user32" _ Alias "SetWindowLongA" ( _ ByVal hwnd As Long, _ ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long ' Pointer zum Original Message Handler des Forms Public lWindowProcOld As Long ' Das Handle des CommonControl welches eigefärbt ' werden soll Public lCCHwnd As Long Public Const GWL_WNDPROC = (-4) ' Hintergrundfarbe Public glbLVWBackColor As Long
Public Function WindowProc(ByVal hwnd As Long, _ ByVal iMsg As Long, ByVal wParam As Long, _ ByVal lParam As Long) As Long ' Die WM_NOTIFY message Dim oNMHDR As NMHDR ' CustomDraw eines ListViews Dim oNMLVCUSTOMDRAW As NMLVCUSTOMDRAW Select Case iMsg ' Uns interessieren nur WM_NOTIFY messages Case WM_NOTIFY ' Ah, da is ja schon eine ;-) ' lParam in eine WM_NOTIFY Struktur kopieren CopyMemory oNMHDR, ByVal lParam, 12& If oNMHDR.hWndFrom = lCCHwnd Then ' Kommt die Message auch vom richtigen Control? If oNMHDR.code = NM_CUSTOMDRAW Then ' Ahh ein CommonControl zeichnet da etwas CopyMemory oNMLVCUSTOMDRAW, ByVal lParam, _ Len(oNMLVCUSTOMDRAW) With oNMLVCUSTOMDRAW.nmcd ' Wo wird gerade gezeichnet Select Case .dwDrawStage Case CDDS_PREPAINT ' PrePaint des ListViews ignorieren ' Windows mitteilen das alle Items ' einzeln gezeichnet werden sollen WindowProc = CDRF_NOTIFYITEMDRAW ' Funktion verlassen und Message dem ' Form "unterschlagen" Exit Function Case CDDS_ITEMPREPAINT ' Hier wird ein ListItem vorgezeichnet ' .dwItemSpec = ListItem Index If (.dwItemSpec Mod 2) = 0 Then ' Bei jedem 2ten Listeneintrag die ' Farbe ändern ' Hintergrundfarbe oNMLVCUSTOMDRAW.clrTextBk = glbLVWBackColor ' Nun die CustomDraw Struktur wieder ' nach lParam kopieren CopyMemory ByVal lParam, oNMLVCUSTOMDRAW, _ Len(oNMLVCUSTOMDRAW) WindowProc = CDRF_NOTIFYITEMDRAW Exit Function End If End Select End With End If ' .code = NM_CUSTOMDRAW End If ' oNMHDR.hWndFrom = lCCHwnd End Select ' iMsg ' Die Message an VB weitergeben WindowProc = CallWindowProc(lWindowProcOld, hwnd, _ iMsg, wParam, lParam) End Function