1 说明
Button文字颜色和背景颜色的改变和其他控件的有所不同,它的改变方法是重写virtual void CButton::DrawItem() 函数
2 步骤
对已存在的一个按钮
①新建一个类CTestBtn, 基类为CButton
②为CTestBtn类增加虚函数,说明中所写的函数,重写代码,下面的例子中会给出MSDN中的Example代码
③把当前的按钮属性中勾选Owner-Draw或者“所有者绘制”
④为该按钮关联一个成员变量,类型为CTestBtn
⑤根据需要在DrawItem()中增加代码,从而改变该按钮的文字颜色和背景色等信息。
3 Example of MSDN
void CTestBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: Add your code to draw the specified item
UINT uStyle = DFCS_BUTTONPUSH;
// This code only works with buttons.
ASSERT(lpDrawItemStruct->CtlType == ODT_BUTTON);
// If drawing selected, add the pushed style to DrawFrameControl.
if (lpDrawItemStruct->itemState & ODS_SELECTED)
uStyle |= DFCS_PUSHED;
// Draw the button frame.
::DrawFrameControl(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem,
DFC_BUTTON, uStyle);
// Get the button's text.
CString strText;
GetWindowText(strText);
// Draw the button text using the text color red.
COLORREF crOldColor = ::SetTextColor(lpDrawItemStruct->hDC, RGB(255,0,0));
::DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(),
&lpDrawItemStruct->rcItem, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
::SetTextColor(lpDrawItemStruct->hDC, crOldColor);
}
该段代码执行后,按钮上文字颜色为红色
分析略
NOTE:DrawItem()函数为虚函数,而非WM_DRAWITEM消息处理函数, 关于区别请看下面转载的文字
3 WM_DRAWITEM与DrawItem()的讨论
来源:http://hi.baidu.com/%CE%DA%C9%AA%B6%FB%D0%A6%C1%CB/blog/item/106248f292f2f6ce7831aa65.html
在学习中经常遇到要重写DrawItem()的情况,但又有一个WM_DRAWITEM消息,它们是什么样的关系呢。
如果我们要重写一个CButton取名为CMyButton,我们可以重写CMyButton的DrawItem()函数来实现我们的需求,但CMyButton::DrawItem()是在什么时候调用呢?它是在它的宿主类的OnDrawItem()中被调用,OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct )正是对WM_DRAWiTEM的相应函数。
宿主类可以根据nIDCtl来判定是哪个子控件。其实我们可以在OnDrawItem函数里对子控件进行绘制,但是有很多的子控件看起来不好,所以我们应该在子类的DrawItem对子类绘制,例如CMyButton::DrawItem。所以可以这样理解,OnDrawItem是画窗口中的子控件的,因为它的入口参数LPDRAWITEMSTRUCT带入不同子控件的相关参数,而且,你得把字控件设置成“自画”类型,才会调用到OnDrawItem。
在学习中还有一个消息也是由宿主类被调用的,它就是WM_CTRCOLOR。这个消息是在子控件将要绘画时,利用反射机制发送给其宿主类。OnCtlColor (CDC* pDC, CWnd* pWnd, UINT nCtlColor),pDC,pWnd都是于子类 相关的,在这里可以设置,前景颜色,背景颜色,画刷类型,字体等等,但不能改变元素的界面框架,这是DrawItem 所能干的。
如果同时有DrawItem(子类),OnDrawItem(宿主类),OnCtlColor(宿主类),它们的调用顺序是: OnCtlColor,OnDrawItem,DrawItem。
如果我们同时又相应的子类的WM_PAINT消息,子类不会向宿主类发送WM_DRAWITEM消息,你要完成子类的 全部绘制工作,如果子类是一个列表框,就很麻烦。这事调用顺序是OnCtlColor,OnPaint。
在发送一个WM_PAINT消息前,总会先发送一个WM_ERASEBACK消息,我们在这里在一个背景图片。
对于我们平时对控件的绘制,上面介绍的差不多了,还有一个CView的问题,也就是OnPaint和Ondraw的关系, 其实这个很简单,CView::OnPaint()的源码如下:
void CView::OnPaint()
{
CPaintDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc)
}
void CView::OnPaint() { CPaintDC dc(this); OnPrepareDC(&dc); OnDraw(&dc) }
从代码中可以清楚的看出他们的关系。
?