这里值得注意的是,还可以将 NMHDR 指针指向特定于正在绘制控件的类型的结构。表 1 显示控件的一个列表及其相关的自定义绘制结构类型名。
表 1:控件及其相关的自定义绘制结构 | |
控件 | 结构(在 commctrl.h 中定义) |
Rebar、Trackbar、AuthTicket、My.Resources、My.Settings、My.User 和 My.WebServices。 | NMCUSTOMDRAW |
List-view | NMLVCUSTOMDRAW |
Toolbar | NMTBCUSTOMDRAW |
Tooltip | NMTTCUSTOMDRAW |
Tree-view | NMTVCUSTOMDRAW |
指定处理所需的绘制阶段
正如我在前面提到的,绘制一个控件存在一些“阶段”。特别是,您可以将绘制过程理解为一系列阶段,其中控件通知其父窗口需要绘制的内容。事实上,控件甚至会在绘制控件及其各项前后发送一个通知,从而让编程人员更好地控制该过程。
在所有情况下,单一的 NM_CUSTOMDRAW 处理程序在每个绘制阶段都进行调用。然而,谨记:自定义绘制允许您在自己的绘制中合并默认的控件绘制,您需要指定您将处理哪个绘制阶段。这通过设置 NM_CUSTOMDRAW 处理程序的第二个参数 (pResult) 完成。事实上,如果您从未设置该值,则用初始阶段的 CDDS_PREPAINT 调用函数后,您的函数将不再被调用!
从技术上讲,只有两个阶段指定需要的绘制阶段(CDDS_PREPAINT 和 CDDS_ITEMPREPAINT),它们影响发送通知消息的内容。然而,通常只在处理程序的最后指定代码将处理的绘制阶段。表 2 列出用于指定所需绘制阶段(代码关注的)的值。
表 2:自定义绘制返回标志 | |
自定义绘制返回标志 | 含义 |
CDRF_DEFAULT | 指示控件自行绘制。该值为默认值,不应该将它与其他值组合在一起。 |
CDRF_SKIPDEFAULT | 用于指定控件根本不进行任何绘制。 |
CDRF_NEWFONT | 当代码更改绘制项/子项的字体时使用。 |
CDRF_NOTIFYPOSTPAINT | 使通知信息在控件或每个项/子项绘制后发送。 |
CDRF_NOTIFYITEMDRAW | 指出项(或子项)将进行绘制。注意,它下面的值与 CDRF_NOTIFYSUBITEMDRAW 相同。 |
CDRF_NOTIFYSUBITEMDRAW | 指出子项(或项)将进行绘制。注意,它下面的值与 CDRF_NOTIFYITEMDRAW 相同。 |
CDRF_NOTIFYPOSTERASE | 当删除控件后需要通知代码时使用。 |
以下为一个示例,其中的代码指定,当绘制控件的项 (CDRF_NOTIFYITEMDRAW) 及子项 (CDRF_NOTIFYPOSTPAINT),以及绘制完成时,应该调用 NM_CUSTOMDRAW 处理程序。
void CListCtrlWithCustomDraw::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult){ LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); *pResult = 0; // Initialize value *pResult |= CDRF_NOTIFYITEMDRAW; *pResult |= CDRF_NOTIFYSUBITEMDRAW; *pResult |= CDRF_NOTIFYPOSTPAINT;}
筛选指定的绘制阶段
一旦指定要关注的阶段后,您需要处理这些阶段。因为绘制过程的每个阶段只有一个消息要发送,惯例是执行一个 switch 语句以决定准确的绘制阶段。不同的绘制阶段由以下标志定义:
CDDS_PREPAINTCDDS_ITEMCDDS_ITEMPREPAINTCDDS_ITEMPOSTPAINTCDDS_ITEMPREERASECDDS_ITEMPOSTERASECDDS_SUBITEMCDDS_POSTPAINTCDDS_PREERASECDDS_POSTERASE
对于一个 CListCtrl 派生的类,有一个 NM_CUSTOMDRAW 处理程序的示例,其中您可以发现,代码决定当前绘制阶段的方式:
void CMyCustomDrawControl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult){ LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); switch(pNMCD->dwDrawStage) { case CDDS_PREPAINT: break; case CDDS