常见的控件自绘的方法有父窗口的OnDrawItem()函数、子控件的OnDrawItem()函数、子控件的CtlColor()函数、子控件的OnPaint()函数,子控件的OnNMCustomdraw()函数等。自绘控件的话需要控件具有Owner Draw属性,通过Create()创建控件的时候添加BS_OWNERDRAW属性,或者在资源视图中右击控件->属性->Owner Draw设为true。
1、父窗口的OnDrawItem()函数、子控件的OnDrawItem()函数
在MFC中子控件要绘制的时候框架就会向父窗口发送WM_DRAWITEM消息,而父窗口会在WM_DRAWITEM消息响应函数OnDrawItem()里调用子控件的DrawItem()函数,所以我们既可以在父窗口的OnDrawItem()函数里也可以在控件的OnDrawItem()函数里进行 控件的绘制,不过一般都是选择在子控件的OnDrawItem()函数里绘制控件。
不是所有设置成自画类型的控件都会调用父窗口的OnDrawItem,例如ListBox的自画,你就必须重载CListBox的DrawItem方法和MeasureItem方法才可以,但按钮、菜单等的自画则会调用OnDrawItem。
2、子控件的CtlColor()函数
子控件开始绘制之前,还会向宿主类发送WM_CTLCOLOR消息,对应的消息响应函数为OnCtlColor,而宿主类收到WM_CTLCOLOR消息后会向子控件发送=WM_CTLCOLOR反射消息,让子控件有一个自己处理绘制的机会(这就是MFC中的消息反射),子控件中=WM_CTLCOLOR消息响应函数为CtlColor()。我们一般在CtlColor中对子控件设置控件的前景颜色、背景颜色、画刷类型、字体等但不能改变元素的界面框架,这是OnDrawItem或DrawItem所能干的。
如果同时有DrawItem(子类),OnDrawItem(宿主类),CtlColor(子类),OnCtlColor (宿主类),则它们的调用顺序是:OnCtlColor—>CtlColor—>OnDrawItem—>DrawItem。
3、子控件的OnPaint()函数
添加了子控件的WM_PAINT消息响应OnPaint,这时就不会向宿主类发送WM_DRAWITEM消息了,这时就需要在子类的OnPaint中完成子控件的全部绘制工作。如果子控件是一个List列表的话,这样做就很麻烦,所以不建议在OnPaint()中进行控件的绘制。
还有就是在发送一个WM_PAINT消息前,总会先发送一个WM_ERASEBACK消息,我们可以在这里添加一个背景图片。
4、子控件的OnNMCustomdraw()函数
一些控件在绘制的时候会向宿主类发送NM_CUSTOMDRAW消息,NM_CUSTOMDRAW是通过WM_NOTIFY发送给父窗口的,父窗口收到后会向子控件发送反射消息=NM_CUSTOMDRAW,子控件的=NM_CUSTOMDRAW反射消息相应函数为OnNMCustomdraw()。