Die Aufgabenstellung selbst erscheint relativ simpel: Man möchte in einer ListBox bzw. in einem ListView einen Eintrag mit einer Hintergrundfarbe hinterlegen, um diesen z.B. besonders hervorzuheben.
Leider unterscheiden sich die Methoden hierfür bei ListBox und ListView erheblich.
Beim ListView ist das Ganze relativ einfach zu lösen:
Das ListView sendet eine
WM_NOTIFY
Message an den Parent-Dialog, der das Control beinhaltet. Als
lParam
erhält man eine
LPNMLISTVIEW
Struktur, welche im
hdr
Member wiederum einen Member
code
enthält, welcher den eigentlichen Notification code angibt. Für das ListView ist hier für uns der Code
NM_CUSTOMDRAW
interessant. Durch Erhalt der Message ist sichergestellt, dass es sich bei der in lParam an uns übergebene Struktur um eine
NMLVCUSTOMDRAW
Struktur handelt. In deren Member
nmcd
befindet sich die zur Message zugehörige Struktur
NMCUSTOMDRAW
, welche wiederum den Member
dwDrawStage
beinhaltet, der uns über den aktuellen Zeichnungsstatus informiert. Erhalten wir hier die Nachricht
CDDS_PREPAINT
, wissen wir, dass das Zeichnen des ListViews gerade beginnt. An dieser Stelle müssen wir nun unser Interesse an den Notifications für die einzelnen Items der Liste anmelden. Das geht ganz einfach mit folgendem Kommando:
SetWindowLong (hWnd, DWL_MSGRESULT, CDRF_NOTIFYITEMDRAW);
Mit besagtem Kommando teilen wir dem Notifier unsere Antwort mit, die da eben lautet
CDRF_NOTIFYITEMDRAW
.
Nun können wir den Drawstage pro Item mit der Nachricht
CDDS_ITEMPREPAINT
dispatchen.
An dieser Stelle können wir nun auf den Zeichenprozess einfluss nehmen, indem wir die Members de rStruktur in lParam entsprechend modifizieren und den Notifier diese Änderung zur Kenntnis bringen.
Hier ein Beispiel, welches den Text rot färbt:
lplvcd->clrText = RGB(255,0,0);
SetWindowLong (hWnd, DWL_MSGRESULT, CDRF_NEWFONT);
Den kompletten Source zur besseren Übersicht gibt's
hier
Bei der ListBox ist das Ganze leider nicht ganz so einfach. Diese bietet nämlich leider keinen so bequemen
WM_NOTIFY
-Mechanismus. Stattdessen muss man sich hier mit einem owner-Drawn control aushelfen, was natürlich einiges an Arbeit mit sich bringt. Daher sollte man als Style für das Control
LBS_OWNERDRAWFIXED
verwenden. Ein
LBS_HASSTRINGS
könnte sich auch als nützlich erweisen.
Bei einem Owner-Drawn control erhält der Parent eine
WM_DRAWITEM
Notification, welche entpsrechend behandelt werden muss.
Als lParam erhält man ein
LPDRAWITEMSTRUCT
, welches den Member
itemAction
hat. Interessant sind hierbei die Actions
ODA_SELECT
und
ODA_DRAWENTIRE
.
Ein Zeichnen des ListBox-Eintrags im entsprehcenden Style erreicht man hier mittels Modifikation des device contexts, welcher sich im
hDC
Member des
DRAWITEMSTRUCT
s befinder.
Je nach
itemState
Member sollte man die Vordergrund- und Hintergrundfarbe des Eintrags entsprechend setzen. Um die Systemfarben zu ermitteln, empfiehlt sich der Einsatz der Funktion
GetSysColor
.Mit
FillRect
die Auswahlmarkierung erzeugen und mit
TextOut
schließlich den Text zeichnen. Also ein relativ hoher Aufwand, um nur die Farbe des Textes zu ändern.
Ein Codebeispiel gibt's wie immer
hier.