关于自定义绘图

本部分包含有关自定义绘图功能的常规信息,并提供应用程序如何支持自定义绘图的概念性概述。 目前,以下控件支持自定义绘图功能:

  • 标头控件
  • 列表视图控件
  • Rebar 控件
  • 工具栏控件
  • 工具提示控件
  • Trackbar 控件
  • 树视图控件

关于自定义绘图通知消息

支持自定义绘图的所有常见控件在绘图作期间在特定点发送 NM_CUSTOMDRAW 通知代码。 这些通知代码描述应用于整个控件的绘图作,以及特定于控件内项的绘图作。 与许多通知代码一样,NM_CUSTOMDRAW通知作为 WM_NOTIFY 消息发送。

自定义绘图通知的 lParam 参数将是 NMCUSTOMDRAW 结构的地址或包含 NMCUSTOMDRAW 结构的特定于控件的结构作为其第一个成员。 下表说明了控件与它们使用的结构之间的关系。

结构 使用者
NMCUSTOMDRAW Rebar、trackbar 和标头控件
NMLVCUSTOMDRAW 列表视图控件
NMTBCUSTOMDRAW 工具栏控件
NMTTCUSTOMDRAW 工具提示控件
NMTVCUSTOMDRAW 树视图控件

绘制周期、绘图阶段和通知消息

与所有 Windows 应用程序一样,常见控件会根据从系统或其他应用程序接收的消息定期绘制和擦除自身。 控件绘画或擦除本身的过程称为 油漆周期。 支持自定义绘图的控件通过每个绘制周期定期发送 NM_CUSTOMDRAW 通知代码。 此通知代码附带 NMCUSTOMDRAW 结构或其他包含 NMCUSTOMDRAW 结构作为其第一个成员的结构。

NMCUSTOMDRAW 结构包含的一条信息是绘制周期的当前阶段。 这称为 绘图阶段 ,由结构 dwDrawStage 成员中的值表示。 控件通知其父级四个基本绘图阶段。 这些基本或全局绘制阶段通过以下标志值(在 Commctrl.h 中定义)在结构中表示。

全局绘制阶段值 DESCRIPTION
CDDS_PREPAINT 在绘制周期开始之前。
CDDS_POSTPAINT 绘制周期完成后。
CDDS_PREERASE 擦除周期开始之前。
CDDS_POSTERASE 擦除周期完成后。

上述每个值都可以与CDDS_ITEM标志结合使用,以指定特定于项的绘制阶段。 为方便起见,Commctrl.h 包含以下特定于项的值。

特定于项目的绘制阶段值 DESCRIPTION
CDDS_ITEMPREPAINT 在绘制项之前。
CDDS_ITEMPOSTPAINT 绘制项目后。
CDDS_ITEMPREERASE 在擦除项目之前。
CDDS_ITEMPOSTERASE 清除项目后。
CDDS_SUBITEM 通用控件版本 4.71。 如果要绘制子项,则标记与CDDS_ITEMPREPAINT或CDDS_ITEMPOSTPAINT结合使用。 仅当 从CDDS_PREPAINT返回CDRF_NOTIFYITEMDRAW 时,才会设置此设置。

应用程序必须处理 NM_CUSTOMDRAW 通知代码,然后返回一个特定值,告知控件必须执行的作。 有关这些返回值的详细信息,请参阅以下部分。

利用自定义绘图服务

利用自定义绘图功能的关键是响应控件发送 的NM_CUSTOMDRAW 通知代码。 应用程序为响应这些通知而发送的返回值决定了该绘制周期的控件行为。

本部分包含有关应用程序如何使用 NM_CUSTOMDRAW 通知返回值来确定控件的行为的信息。

详细信息分为以下主题:

响应预付费通知

在每个绘制周期的开头,该控件发送 NM_CUSTOMDRAW 通知代码,并在随附NM_CUSTOMDRAW结构的 dwDrawStage 成员中指定CDDS_PREPAINT值。 应用程序返回到此第一个通知的值决定了控件如何以及何时为该绘制周期的其余部分发送后续自定义绘图通知。 应用程序可以返回以下标志的组合,以响应第一个通知。

返回值 影响
CDRF_DODEFAULT 控件将自行绘制。 它不会为此绘制周期发送其他 NM_CUSTOMDRAW 通知。 此标志不能与任何其他标志一起使用。
CDRF_DOERASE 该控件将仅绘制背景。
CDRF_NEWFONT 应用程序为项目指定了新字体;控件将使用新字体。 有关更改字体的详细信息,请参阅 更改字体和颜色。 当 dwDrawStage 等于CDDS_ITEMPREPAINT时,会出现这种情况。
CDRF_NOTIFYITEMDRAW 该控件将通知父级任何特定于项的绘图作。 它将在绘制项目之前和之后发送 NM_CUSTOMDRAW 通知代码。 当 dwDrawStage 等于CDDS_PREPAINT时,将发生这种情况。
CDRF_NOTIFYPOSTERASE 删除项后,控件将通知父级。 当 dwDrawStage 等于CDDS_PREPAINT时,会出现这种情况。
CDRF_NOTIFYPOSTPAINT 当整个控件的绘制周期完成时,该控件将发送 NM_CUSTOMDRAW 通知。 当 dwDrawStage 等于CDDS_PREPAINT时,会出现这种情况。
CDRF_NOTIFYSUBITEMDRAW 版本 4.71。 应用程序将收到 NM_CUSTOMDRAW 通知, dwDrawStage 设置为 CDDS_ITEMPREPAINT |在绘制每个列表视图子项之前CDDS_SUBITEM。 然后,可以单独为每个子项指定字体和颜色,或者返回默认处理 CDRF_DODEFAULT 。 当 dwDrawStage 等于CDDS_ITEMPREPAINT时,会出现这种情况。
CDRF_SKIPDEFAULT 应用程序手动绘制项目。 控件不会绘制项。 当 dwDrawStage 等于CDDS_ITEMPREPAINT时,会出现这种情况。
CDRF_SKIPPOSTPAINT 控件不会在项周围绘制焦点矩形。

请求特定于项目的通知

如果应用程序 将CDRF_NOTIFYITEMDRAW 返回到初始预付费自定义绘图通知,该控件将在该绘制周期内为其绘制的每个项目发送通知。 这些特定于项的通知将具有随附 NMCUSTOMDRAW 结构的 dwDrawStage 成员中的 CDDS_ITEMPREPAINT 值。 可以通过将 CDRF_NOTIFYPOSTPAINT 返回到这些项目特定的通知,请求控件在完成绘制项目时发送另一个通知。 否则, 返回CDRF_DODEFAULT ,控件在开始绘制下一项之前不会通知父窗口。

自行绘制项目

如果应用程序绘制整个项,则返回 CDRF_SKIPDEFAULT。 这样,控件就可以跳过不需要绘制的项,从而减少系统开销。 请记住,返回此值意味着控件不会绘制项的任何部分。

更改字体和颜色

应用程序可以使用自定义绘图来更改项目的字体。 只需在与自定义绘图通知关联的 NMCUSTOMDRAW 结构的 hdc 成员指定的设备上下文中选择所需的 HFONT。 由于所选字体的指标可能与默认字体不同,因此请确保在通知消息的返回值中包含 CDRF_NEWFONT 位。 有关使用此功能的详细信息,请参阅 “使用自定义绘图”中的示例代码。 应用程序指定的字体用于在未选中该项时显示该项目。 自定义绘图不允许更改所选项目的字体属性。

若要更改支持自定义绘图的所有控件的文本颜色,除了列表视图和树视图之外,只需使用 SetTextColorSetBkColor 函数在自定义绘图通知结构中提供的设备上下文中设置所需的文本和背景色。 若要修改列表视图或树视图中的文本颜色,需要在 NMLVCUSTOMDRAWNMTVCUSTOMDRAW 结构的 clrText 和 clrTextBk 成员中放置所需的颜色值。

注释

在公共控件 版本 6.0 之前,工具栏将忽略 CDRF_NEWFONT 标志。 版本 6.0 支持 CDRF_NEWFONT 标志,你可以使用它为工具栏选择其他字体。 但是,当视觉样式处于活动状态时,无法更改工具栏的颜色。 若要在版本 6.0 中更改工具栏的颜色,必须先通过调用 SetWindowTheme 并指定无视觉样式来禁用视觉样式:

SetWindowTheme (hwnd, "", "");

使用 List-View 和 Tree-View 控件进行自定义绘图

最常见的控件基本上可以采用相同的方式进行处理。 但是,列表视图和树视图控件具有一些功能,这些功能需要一些不同的自定义绘制方法。

对于 版本 5.0,如果通过返回 CDRF_NEWFONT更改字体,这两个控件可能会显示剪裁的文本。 此行为是与早期版本的常见控件向后兼容所必需的。 如果要更改列表视图或树视图控件的字体,如果在向控件添加任何项之前发送了 wParam 值设置为 5 的CCM_SETVERSION消息,则获得更好的结果。

使用 List-View 控件进行自定义绘图

由于列表视图控件具有子项和多个显示模式,因此需要处理 NM_CUSTOMDRAW 通知的方式与其他常见控件稍有不同。

对于报表模式,请使用以下过程。

  1. 第一个NM_CUSTOMDRAW通知将关联 NMCUSTOMDRAW 结构的 dwDrawStage 成员设置为CDDS_PREPAINT。 返回 CDRF_NOTIFYITEMDRAW
  2. 然后,将收到一条 NM_CUSTOMDRAW 通知, dwDrawStage 设置为CDDS_ITEMPREPAINT。 如果指定新字体或颜色并返回 CDRF_NEWFONT,则项目的所有子项都将更改。 如果要单独处理每个子项,请返回 CDRF_NOTIFYSUBITEMDRAW
  3. 如果在上一步中返回 了CDRF_NOTIFYSUBITEMDRAW ,则会收到一条 NM_CUSTOMDRAW 通知,其中 dwDrawStage 设置为 CDDS_SUBITEM |CDDS_ITEMPREPAINT。 若要更改该子项的字体或颜色,请指定新的字体或颜色并返回 CDRF_NEWFONT

对于大型图标、小图标和列表模式,请使用以下过程。

  1. 第一个NM_CUSTOMDRAW通知将关联 NMCUSTOMDRAW 结构的 dwDrawStage 成员设置为CDDS_PREPAINT。 返回 CDRF_NOTIFYITEMDRAW
  2. 然后,将收到一条 NM_CUSTOMDRAW 通知, dwDrawStage 设置为CDDS_ITEMPREPAINT。 可以通过指定新的字体和颜色并返回 CDRF_NEWFONT来更改项目的字体或颜色。 由于这些模式没有子项,因此不会收到任何其他NM_CUSTOMDRAW通知。

有关列表视图 NM_CUSTOMDRAW 通知处理程序的示例,请参阅 “使用自定义绘图”。