About Custom 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:

  • Header controls
  • List-view controls
  • Rebar controls
  • Toolbar controls
  • Tooltip controls
  • Trackbar controls
  • Tree-view controls

About Custom Draw Notification Messages

All common controls that support custom draw send NM_CUSTOMDRAW notification codes at specific points during drawing operations. These notification codes describe drawing operations that apply to the entire control as well as drawing operations specific to items within the control. Like many notification codes, NM_CUSTOMDRAW notifications are sent as WM_NOTIFY messages.

The lParam parameter of a custom draw notification 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

 

Paint Cycles, Drawing Stages, and Notification Messages

Like all 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 codes periodically through each paint cycle. This notification code 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 Description
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 Description
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.
CDDS_SUBITEM Common Control Versions 4.71. Flag combined with CDDS_ITEMPREPAINT or CDDS_ITEMPOSTPAINT if a subitem is being drawn. This will only be set if CDRF_NOTIFYITEMDRAW is returned from CDDS_PREPAINT.

 

Your application must process the NM_CUSTOMDRAW notification code 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.

Taking Advantage of Custom Draw Services

The key to harnessing custom draw functionality is in responding to the NM_CUSTOMDRAW notification codes 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:

Responding to the prepaint notification

At the beginning of each paint cycle, the control sends the NM_CUSTOMDRAW notification code, specifying the CDDS_PREPAINT value in the dwDrawStage member of the accompanying NM_CUSTOMDRAW 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_DOERASE The control will only draw the background.
CDRF_NEWFONT Your application specified a new font for the item; the control will use the new font. For more information on changing fonts, see Changing fonts and colors. This occurs when dwDrawStage equals CDDS_ITEMPREPAINT.
CDRF_NOTIFYITEMDRAW The control will notify the parent of any item-specific drawing operations. It will send NM_CUSTOMDRAW notification codes before and after it draws items.This occurs when dwDrawStage equals CDDS_PREPAINT.
CDRF_NOTIFYPOSTERASE The control will notify the parent after erasing an item. This occurs when dwDrawStage equals CDDS_PREPAINT.
CDRF_NOTIFYPOSTPAINT The control will send an NM_CUSTOMDRAW notification when the painting cycle for the entire control is complete. This occurs when dwDrawStage equals CDDS_PREPAINT.
CDRF_NOTIFYSUBITEMDRAW Version 4.71. Your application will receive an NM_CUSTOMDRAW notification with dwDrawStage set to CDDS_ITEMPREPAINT | CDDS_SUBITEM before each list-view subitem is drawn. You can then specify font and color for each subitem separately or return CDRF_DODEFAULT for default processing. This occurs when dwDrawStage equals CDDS_ITEMPREPAINT.
CDRF_SKIPDEFAULT Your application drew the item manually. The control will not draw the item. This occurs when dwDrawStage equals CDDS_ITEMPREPAINT.
CDRF_SKIPPOSTPAINT The control will not draw the focus rectangle around an item.

 

Requesting item-specific notifications

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.

Drawing the item yourself

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.

Changing fonts and colors

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.

Note

Prior to Version 6.0 of the common controls, toolbars ignore the CDRF_NEWFONT flag. Version 6.0 supports the CDRF_NEWFONT flag, and you can use it to select a different font for the toolbar. However, you cannot change a toolbar's color when a visual style is active. To change a toolbar's color in Version 6.0, you must first disable visual styles by calling SetWindowTheme and specifying no visual style:

 

SetWindowTheme (hwnd, "", "");

Custom Draw With List-View and Tree-View Controls

Most common controls can be handled in essentially the same way. However, the list-view and tree-view controls have some features that require a somewhat different approach to custom draw.

For Version 5.0, these two controls may display clipped text if you change the font by returning CDRF_NEWFONT. This behavior is necessary for backward compatibility with earlier versions of the common controls. If you want to change the font of a list-view or tree-view control, you will get better results if you send a CCM_SETVERSION message with the wParam value set to 5 before adding any items to the control. For an example of a tree-view control that uses custom draw see Knowledge Base article SAMPLE: CustDTv Illustrates Custom Draw in a TreeView (Q248496).

Custom Draw With List-View Controls

Because list-view controls have subitems and multiple display modes, you will need to handle the NM_CUSTOMDRAW notification somewhat differently than for the other common controls.

For report mode, use the following procedure.

  1. The first NM_CUSTOMDRAW notification will have the dwDrawStage member of the associated NMCUSTOMDRAW structure set to CDDS_PREPAINT. Return CDRF_NOTIFYITEMDRAW.
  2. You will then receive an NM_CUSTOMDRAW notification with dwDrawStage set to CDDS_ITEMPREPAINT. If you specify new fonts or colors and return CDRF_NEWFONT, all subitems of the item will be changed. If you want instead to handle each subitem separately, return CDRF_NOTIFYSUBITEMDRAW.
  3. If you returned CDRF_NOTIFYSUBITEMDRAW in the previous step, you will then receive an NM_CUSTOMDRAW notification for each subitem with dwDrawStage set to CDDS_SUBITEM | CDDS_ITEMPREPAINT. To change the font or color for that subitem, specify a new font or color and return CDRF_NEWFONT.

For the large icon, small icon, and list modes, use the following procedure.

  1. The first NM_CUSTOMDRAW notification will have the dwDrawStage member of the associated NMCUSTOMDRAW structure set to CDDS_PREPAINT. Return CDRF_NOTIFYITEMDRAW.
  2. You will then receive an NM_CUSTOMDRAW notification with dwDrawStage set to CDDS_ITEMPREPAINT. You can change the fonts or colors of an item by specifying new fonts and colors and returning CDRF_NEWFONT. Because these modes do not have subitems, you will not receive any additional NM_CUSTOMDRAW notifications.

For an example of a list-view NM_CUSTOMDRAW notification handler, see Using Custom Draw.

Conceptual

Using Custom Draw

Custom Draw Reference

Other Resources

SAMPLE: CustDTv Illustrates Custom Draw in a TreeView (Q248496)