
Custom draw is not a common control; it is a service that many common controls provide. Custom draw services allow an application greater flexibility in customizing a control's appearance. Your application can harness custom draw notifications to easily change the font used to display items or manually draw an item without having to do a full-blown owner draw.
This section contains general information about custom draw functionality and provides a conceptual overview of how an application can support custom draw.
Currently, the following controls support custom draw functionality:
Note Custom draw is implemented in version 4.70 and later of Comctl32.dll.
All common controls that support custom draw send NM_CUSTOMDRAW notification messages at specific points during drawing operations. These notifications describe drawing operations that apply to the entire control as well as drawing operations specific to items within the control. Like many notification messages, NM_CUSTOMDRAW notifications are sent as WM_NOTIFY messages.
The lParam parameter of a custom draw notification message will be the address of an NMCUSTOMDRAW structure or a control-specific structure that contains an NMCUSTOMDRAW structure as its first member. The following table illustrates the relationship between the controls and the structures they use.
| Structure | Used by |
| NMCUSTOMDRAW | Rebar, trackbar, and header controls |
| NMLVCUSTOMDRAW | List view controls |
| NMTBCUSTOMDRAW | Toolbar controls |
| NMTTCUSTOMDRAW | Tooltip controls |
| NMTVCUSTOMDRAW | Tree view controls |
Like all Microsoft® Windows® applications, common controls periodically paint and erase themselves based on messages received from the system or other applications. The process of a control painting or erasing itself is called a paint cycle. Controls that support custom draw send NM_CUSTOMDRAW notification messages periodically through each paint cycle. This notification message is accompanied by an NMCUSTOMDRAW structure or another structure that contains an NMCUSTOMDRAW structure as its first member.
One piece of information that the NMCUSTOMDRAW structure contains is the current stage of the paint cycle. This is referred to as the draw stage and is represented by the value in the structure's dwDrawStage member. A control informs its parent about four basic draw stages. These basic, or global, draw stages are represented in the structure by the following flag values (defined in Commctrl.h).
| Global draw stage values | |
| CDDS_PREPAINT | Before the paint cycle begins. |
| CDDS_POSTPAINT | After the paint cycle is complete. |
| CDDS_PREERASE | Before the erase cycle begins. |
| CDDS_POSTERASE | After the erase cycle is complete. |
Each of the preceding values can be combined with the CDDS_ITEM flag to specify draw stages specific to items. For convenience, Commctrl.h contains the following item-specific values.
| Item-specific draw stage values | |
| CDDS_ITEMPREPAINT | Before an item is drawn. |
| CDDS_ITEMPOSTPAINT | After an item has been drawn. |
| CDDS_ITEMPREERASE | Before an item is erased. |
| CDDS_ITEMPOSTERASE | After an item has been erased. |
Your application must process the NM_CUSTOMDRAW notification message and then return a specific value that informs the control what it must do. See the following sections for more information about these return values.
The key to harnessing custom draw functionality is in responding to the NM_CUSTOMDRAW notification messages that a control sends. The return values your application sends in response to these notifications determine the control's behavior for that paint cycle.
This section contains information about how your application can use NM_CUSTOMDRAW notification return values to determine the control's behavior. Details are broken into the following topics:
At the beginning of each paint cycle, the control sends the NM_CUSTOMDRAW notification message, specifying the CDDS_PREPAINT value in the dwDrawStage member of the accompanying NMCUSTOMDRAW structure. The value that your application returns to this first notification dictates how and when the control sends subsequent custom draw notifications for the rest of that paint cycle. Your application can return a combination of the following flags in response to the first notification.
| Return value | Effect |
| CDRF_DODEFAULT | The control will draw itself. It will not send additional NM_CUSTOMDRAW notifications for this paint cycle. This flag cannot be used with any other flag. |
| CDRF_NOTIFYITEMDRAW | The control will notify the parent of any item-specific drawing operations. It will send NM_CUSTOMDRAW notification messages before and after it draws items. |
| CDRF_NOTIFYPOSTPAINT | The control will send an NM_CUSTOMDRAW notification when the painting cycle for the entire control is complete. |
| CDRF_SKIPDEFAULT | The control will not perform any painting at all. |
If your application returns CDRF_NOTIFYITEMDRAW to the initial prepaint custom draw notification, the control will send notifications for each item it draws during that paint cycle. These item-specific notifications will have the CDDS_ITEMPREPAINT value in the dwDrawStage member of the accompanying NMCUSTOMDRAW structure. You can request that the control send another notification when it is finished drawing the item by returning CDRF_NOTIFYPOSTPAINT to these item-specific notifications. Otherwise, return CDRF_DODEFAULT and the control will not notify the parent window until it starts to draw the next item.
If your application draws the entire item, return CDRF_SKIPDEFAULT. This allows the control to skip items that it does not need to draw, thereby decreasing system overhead. Keep in mind that returning this value means the control will not draw any portion of the item.
Your application can use custom draw to change an item's font. Simply select the HFONT you want into the device context specified by the hdc member of the NMCUSTOMDRAW structure associated with the custom draw notification. Since the font you select might have different metrics than the default font, make sure you include the CDRF_NEWFONT bit in the return value for the notification message. For more information on using this functionality, see the sample code in Using Custom Draw. The font that your application specifies is used to display that item when it is not selected. Custom draw does not allow you to change the font attributes for selected items.
To change text colors for all controls that support custom draw except for the list view and tree view, simply set the desired text and background colors in the device context supplied in the custom draw notification structure with the SetTextColor and SetBkColor functions. To modify the text colors in the list view or tree view, you need to place the desired color values in the clrText and clrTextBk members of the NMLVCUSTOMDRAW or NMTVCUSTOMDRAW structure.
The following application-defined function processes custom draw notification messages sent by a child list view control. Upon receiving the prepaint notification (CDDS_PREPAINT), the function requests item-specific notifications by returning CDRF_NOTIFYITEMDRAW. When it receives the subsequent item-specific notifications, it selects a previously created font into the provided device context and specifies new colors before returning CDRF_NEWFONT.
LRESULT DoNotify(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
LPNMLISTVIEW pnm = (LPNMLISTVIEW)lParam;
switch (pnm->hdr.code){
case NM_CUSTOMDRAW:{
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
/*
CDDS_PREPAINT is at the beginning of the paint cycle. You
implement custom draw by returning the proper value. In this
case, we're requesting item-specific notifications.
*/
if(lplvcd->nmcd.dwDrawStage == CDDS_PREPAINT)
// Request prepaint notifications for each item.
return CDRF_NOTIFYITEMDRAW;
/*
Because we returned CDRF_NOTIFYITEMDRAW in response to
CDDS_PREPAINT, CDDS_ITEMPREPAINT is sent when the control is
about to paint an item.
*/
if(lplvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT){
/*
To change the font, select the desired font into the
provided HDC. We're changing the font for every third item
in the control, starting with item zero.
*/
if(!(lplvcd->nmcd.dwItemSpec % 3))
SelectObject(lplvcd->nmcd.hdc, g_hNewFont);
else
return(CDRF_DODEFAULT);
/*
To change the text and background colors in a list view
control, set the clrText and clrTextBk members of the
NMLVCUSTOMDRAW structure to the desired color.
This differs from most other controls that support
CustomDraw. To change the text and background colors for
the others, call SetTextColor and SetBkColor on the provided HDC.
*/
lplvcd->clrText = RGB(150, 75, 150);
lplvcd->clrTextBk = RGB(255,255,255);
/*
We changed the font, so we're returning CDRF_NEWFONT. This
tells the control to recalculate the extent of the text.
*/
return CDRF_NEWFONT;
}
}
default:
break;
}
return 0;
}
This section contains information about the API elements used for performing custom draw.
| Notifications |
| NM_CUSTOMDRAW |
| NM_CUSTOMDRAW (header) |
| NM_CUSTOMDRAW (list view) |
| NM_CUSTOMDRAW (rebar) |
| NM_CUSTOMDRAW (toolbar) |
| NM_CUSTOMDRAW (tooltip) |
| NM_CUSTOMDRAW (trackbar) |
| NM_CUSTOMDRAW (tree view) |
| Structures |
| NMCUSTOMDRAW |
| NMLVCUSTOMDRAW |
| NMTBCUSTOMDRAW |
| NMTTCUSTOMDRAW |
| NMTVCUSTOMDRAW |
This section contains information about the notification message sent by controls that support custom draw.
NM_CUSTOMDRAW
#ifdef LIST_VIEW_CUSTOM_DRAW
lpNMCustomDraw = (LPNMLVCUSTOMDRAW) lParam;
#elif TOOL_TIPS_CUSTOM_DRAW
lpNMCustomDraw = (LPNMTTCUSTOMDRAW) lParam;
#elif TREE_VIEW_CUSTOM_DRAW
lpNMCustomDraw = (LPNMTVCUSTOMDRAW) lParam;
#elif TOOL_BAR_CUSTOM_DRAW
lpNMCustomDraw = (LPNMTBCUSTOMDRAW) lParam;
#else
lpNMCustomDraw = (LPNMCUSTOMDRAW) lParam;
#endif
Sent by some common controls to notify their parent windows about drawing operations. This notification is sent in the form of a WM_NOTIFY message.
Currently, the following controls support custom draw functionality: header, list view, rebar, toolbar, tooltip, trackbar, and tree view.
When dwDrawStage equals CDDS_PREPAINT:
|
When dwDrawStage equals CDDS_ITEMPREPAINT:
|
Version 4.70
See also Using Custom Draw
This section contains information about the structures used by controls that support custom draw.
typedef struct tagNMCUSTOMDRAWINFO {
NMHDR hdr;
DWORD dwDrawStage;
HDC hdc;
RECT rc;
DWORD dwItemSpec;
UINT uItemState;
LPARAM lItemlParam;
} NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW;
Contains information specific to an NM_CUSTOMDRAW notification message.
| Global draw stage values | |
| CDDS_POSTERASE | After the erasing cycle is complete. |
| CDDS_POSTPAINT | After the painting cycle is complete. |
| CDDS_PREERASE | Before the erasing cycle begins. |
| CDDS_PREPAINT | Before the painting cycle begins. |
| Item-specific draw stage values | |
| CDDS_ITEM | Indicates that the dwItemSpec, uItemState, and lItemlParam members are valid. |
| CDDS_ITEMPOSTERASE | After an item has been erased. |
| CDDS_ITEMPOSTPAINT | After an item has been drawn. |
| CDDS_ITEMPREERASE | Before an item is erased. |
| CDDS_ITEMPREPAINT | Before an item is drawn. |
| CDDS_SUBITEM | Version 4.71. Flag combined with CDDS_ITEMPREPAINT or CDDS_ITEMPOSTPAINT if a subitem is being drawn. This will only be set if CDRF_NOTIFYSUBITEMDRAW is returned from CDDS_PREPAINT. |
| CDIS_CHECKED | The item is checked. |
| CDIS_DEFAULT | The item is in its default state. |
| CDIS_DISABLED | The item is disabled. |
| CDIS_FOCUS | The item is in focus. |
| CDIS_GRAYED | The item is grayed. |
| CDIS_HOT | The item is currently under the pointer ("hot"). |
| CDIS_INDETERMINATE | The item is in an indeterminate state. |
| CDIS_MARKED | The item is marked. The meaning of this is up to the implementation. |
| CDIS_SELECTED | The item is selected. |
Version 4.70
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.