问题引出
在MFC中有个WM_CTLCOLOR消息,它的消息响应函数是CWnd类的OnCtlColor,其函数声明和注释如下:
afx_msg HBRUSH OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor ); 返回值:OnCtlColor必须返回一个刷子句柄,该刷子将被用于画出控件的背景。 参数: pDC 包含了子窗口的显示设备环境的指针。可能是临时的。 PWnd 包含了要求颜色的控件的指针。可能是临时的。 NCtlColor 包含了下列值,指定了控件的类型: · CTLCOLOR_BTN 按钮控件 · CTLCOLOR_DLG 对话框 · CTLCOLOR_EDIT 编辑控件 · CTLCOLOR_LISTBOX 列表框控件 · CTLCOLOR_MSGBOX 消息框 · CTLCOLOR_SCROLLBAR 滚动条控件 · CTLCOLOR_STATIC 静态控件
该函数的返回值将被用来绘制控件的背景。当一个子控件将要被绘制时,它都要向的的父窗口(通常是一个对话框)发生一个WM_CTLCOLOR消息来准备一个DC,以便使用正确的颜色来绘制该控件。OnCtlColor默认的函数实现如下:
HBRUSH CDrawMainDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); //如果默认的不是所需画笔,则返回另一个画笔 //CBrush 对象 return m_brush; }我们注意到,OnCtlColor函数要求返回HBRUSH类型的句柄,而默认的函数返回的却是CBrush类型的画刷对象。这其中的原因就是CBrush类重载了HBRUSH操作符。HBRUSH操作符重载声明如下:
operator HBRUSH( ) const;调用成功时该操作符返回一个指向Windows GDI对象的句柄,该句柄表示一个CBrush对象,否则返回NULL。
现在的问题就是请说明如何将CBrush对象转换为一个HBRUSH句柄,在回答这个问题之前我们先了解下GDI对象,重载,强制类型转换这个三个知识点。
补充知识
GDI对象
微软提供了各种Windows图形设备接口(GDI)对象,如位图(CBitmap)、区域(CRgn)、画刷(CBrush)、画笔(CPen)、调色板(CPalette)、字体(CFont)的等类型,这些类类型对象可以用于相关图形的绘制工作,它们都有相同的父类CGdiObject,m_hObject是CGdiObject的数据成员,包含附加给对象的HBITMAP,HPALETTE,HRGN,HBRUSH,HPEN或HFONT的句柄。也就是说CPen、CBrush等对象都各自包含了相对应的句柄。
强制类型转换
当操作数的类型不同,经常需要将操作数转化为所需要的类型,这个过程即为强制类型转换。强制类型转换具有两种形式:显式强制转换和隐式强制类型转换。
显式强制转换
形如“TYPE b = (TYPE) a”的表达式都是显示强制类型转换,这种转换有明显的转换过程,即括号和类型组合(TYPE)。
隐式类型转换
这类型转换发生在赋值表达式和有返回值的函数调用表达式中。在赋值表达式中,如果赋值符左右两侧的操作数类型不同,则将赋值符右边操作数强制转换为赋值符左侧的类型数值后,赋值给赋值符左侧的变量。在函数调用时,如果return后面表达式的类型与函数返回值类型不同,则在返回值时将return后面表达式的数值强制转换为函数返回值类型后,再将值返回。
操作符重载
操作符重载包含两个要素:operator 和被重载的字符,CBrush类被重载的字符就是"HBRUSH",当在CBrush类中,当遇到HBRUSH类型转换时,被转换的CBrush对象会调用operator HBRUSH()运算符重载函数,在其中的GDI类型中也都有相对应的运算符重载接口,它们的原理也都是一样的。
HBRUSH运算符重载实现
在OnCtlColor函数中我们直接返回了CBrush类的对象,由于该函数要求返回的是HBRUSH句柄,两者类型不一致,发生隐式类型转换,即存在这个的过程“HBRUSH hTemp = (HBRUSH)m_brush”->m_brush.operatro HBRUSH()。m_brush对象调用了运算符重载函数,在该函数中返回了对应的句柄,函数大致实现如下:
HBRUSH operator HBRUSH() { return this.m_hObject;//指向CBrush对象的句柄 }