Coded
Article: Custom Draw(ing) the ListView's Header Control
(By Damon
Chandler)
Adding small
glyphs to a ListView's header control is common practice in many applications.
This is easily accomplished and outlined in the CAQ: Adding
Bitmaps to a ListView's Header Control. However, perhaps you'd
like to change the background color of the header, or draw a bitmap transparently
in a certain header section. While Windows allows the header control
to be owner-drawn as discussed in the CAQ: Drawing
on a ListView's Header Control, this approach will only work
for API created ListViews or TListViews from BCB1. More specifically,
the header loses it's owner-drawn style upon column resizing. Obviously
this is an unintentional side effect of some type of header manipulation
in newer versions of the VCL.
Fortunately, like many of the common
controls, the header control provides the Custom Draw service. This
is, in fact, more powerful than an owner-drawn approach. As mentioned
in the CAQ: An Introduction to Custom Draw,
this requires comctl32 version 4.70+ (IE 3). There are very few MSDN
examples on Custom Draw, but fortunately, the techniques are similar for
all common controls. Custom Draw is nothing more than a fancy communication
between you and Windows. Windows sends you messages that drawing
is about to begin (CDDS_PREPAINT). You respond by telling Windows
what drawing stages you want notification of, in this case CDRF_NOTIFYITEMDRAW
for each header section. Windows then responds by sending you messages
corresponding to each header section being drawn (CDDS_ITEMPREPAINT).
Finally, you draw the header section, then respond to Windows by telling
it that you drew the header (CDRF_SKIPDEFAULT), so that it doesn't draw
the header again.
While BCB4+ encapsulates the Custom
Draw service for TListView and TTreeView controls, it does not do so for
header controls. In fact, it is probably a good idea to learn Custom
Draw the API way, as there are other common controls that allow the service
for which the VCL provides no Custom Draw encapsulation. The ToolBar
and TrackBar controls are some examples of this.
Since Custom Draw messages are sent
to the parent of the control, and the header control is a child of the
ListView, you'll need to subclass the ListView and handle the WM_NOTIFY
message in the subclass procedure. This is easily accomplished via
the WindowProc property. In the subclass procedure, handle the WM_NOTIFY
message and test the code member of the NMHDR member of the NMCUSTOMDRAWstructure
(sent as the LParam) for the NM_CUSTOMDRAW notification. Also, test
the hwndFrom member of the NMHDR to make sure the
notification corresponds to the header control. From there, simply
test the drawing stage and respond with the correct CDRF_* constant (response
flag). The following list describes the information conveyed
in each member of the NMCUSTOMDRAW structure:
typedef
struct tagNMCUSTOMDRAWINFO
{
NMHDR hdr; <--- This
the the NMHDR structure that describes the sender
of the message and the actual type of notification
(we're looking for NM_CUSTONDRAW in thie case).
DWORD dwDrawStage; <---This
member reports the drawing stage of the
Custom Draw process (CDDS_*).
HDC hdc; <---This
member is a handle to the device context to draw on.
RECT rc; <---This
member is the rectangle of the particular header
section referred to by the dwItemSpec member.
DWORD dwItemSpec; <---This
member reports the zero-based index of the
current header section that is being drawn.
UINT uItemState; <---This
member reports the state of the item
(e.g., pushed, hot, focused, etc.). It can be
a combination of one or more of the CDIS_*
constants.
LPARAM lItemlParam; <---extra
information associated with each item
}
NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW;
KEYWORDS: WM_NOTIFY, Custom
Draw
REFERENCES: http://msdn.microsoft.com/library/sdkdoc/shellcc/commctls/CustDraw/CustDraw.htm
|