对于Windows 的标准控件(button, edit boxes etc),我们也可以用WM_CTLCOLOR通知消息去做一些简单的改变,通常是针对使用的颜色做改变。在画控件的循环过程中,Windows会发送WM_CTLCOLOR消息给你,使你有机会去改变设备上下文和指定一个用来画背景的画刷。在这种模式下你能做的事多少会有些受限,但是很有利的一点是控件仍然自己会做大量的工作;你不需要告诉它怎样去画。尽管如此,这些消息仅仅对Windows的标准控件有效;Windows的普通控件不支持WM_CTLCOLOR。
Custom Draw
Windows普通控件添加了另一种客制化的方法称作“custom draw”。这种方法不同于owner draw, 尽管一些程序员将这2者混淆。Custom draw可用于ListView, TreeView, ToopTip, Header, TrackBar, Toolbar以及Rebar 控件。
Custom draw使你进入控件绘画的循环中的一个或多个绘画阶段。每一个绘画阶段你可以对绘画的内容做改变,并且可以选择去做你自己的绘画动作,或者让控件去做绘画动作,又或者将这2者相结合来用。在绘画循环过程中,你也可以得到控件较后时间发生的控制消息。
NM_CUSTOMDRAW Notifications
假如绘画阶段(draw stage)设置为CDDS_PREPAINT. 那么当控件第一次开始画自己的时候,作为WM_PAINT消息的响应,你会接收到一个NM_CUSTOMDRAW通知消息。如果你不做处理,那么这次绘画将会结束,因为默认的消息句柄会告诉控件去执行默认的绘画工作并且不要再中断你。
如果你处理了这个消息,那么只要你愿意,你就可以自己去做大量的绘画工作。你可以随后设置一个返回结果的标志,这个结果表示了你是否希望这个控件去做它默认的绘画动作,通常情况你是希望的这样做的。你也可以设置一个返回结果的标志来表示你是否希望收到之后的通知消息。你可以要求控件给你发送一条WM_CUSTOMDRAW消息,在绘画阶段为CDDS_POSTPAINT的时候,这个时候表示控件已经完成了绘画(你自己随后可以做一些额外的绘画动作)。你也可以将返回标志设置成表示你希望得到CDDS_ITEMPREPAINT 绘画阶段的通知,每个item画的时候都会响应该消息。
类似的,当你得到了CDDS_ITEMPREPAINT阶段的每个WM_CUSTOMDRAW通知,你可以设定使用的颜色,对设备上下文包括字体做改变,可能再做一些你自己的绘画工作。你可以随后决定你是否希望默认画这个item, 或当这个item的绘画已经完成时,你是否希望得到CDDS_ITEMPOSTPAINT的消息通知,
如果你在report模式,你也可以要求每一个subitem的通知,他们有对应设置的绘画阶段(CDDS_ITEMPREPAINT | CDDS_SUBITEM),这样你又可以修改设备上下文,做你自己的绘画,又或让控件做绘画,然后在每个subitem绘画结束时得到一个(CDDS_ITEMPOSTPAINT | CDDS_SUBITEM)绘画阶段消息。
注意:subitem通知仅仅对Custom 控件V4.71(就是IE4.0,或Windows 98)或之后的有用,所以请确保你选择COMCTL32的版本在你的机器上,如果你打算使用custom draw控制。
Why Custom Draw
现在,让我们来比较一下Custom draw比Owner draw在ListView控件中的具有的优势:
为了实现这样的灵活性,为NM_CUSTOMDRAW写消息处理是比较复杂的,所有不同的绘画阶段都通过一个消息处理句柄来响应。必须理解怎样控制每一个绘画阶段的行为动作,从NMLVCUSTOMDRAW结构体来获取需要的信息,并设置恰当的标志以便于正确的接收到一系列的通知消息。
但是事情事实上更加的复杂。一些在NMLVCUSTOMDRAW结构体中的信息只能在特定的绘画阶段中是有意义的。例如,Windows设置iSubItem值仅对于sub items通知时是有效的,在其他通知消息中它的值就是没有意义的。类似的,在一些绘画阶段Windows仅填写结构体的RECT值(取决于你的普通控件的版本)。实验结果显示即使不是完全恰当的,但事实上在一些绘画阶段中只有一些值是有效的而其它值是无效的。