在默认情况下, 我们看到的对话框及其控件的背景和字体颜色都是浅灰色的,为了美化界面我们可以使用MFC中的WM_CTLCOLOR消息,它的响应函数是Cwnd类的OnCtlColor.。该函数声明如下:
afx_msg HBRUSH OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor ); 返回值:OnCtlColor必须返回一个刷子句柄,该刷子将被用于画出控件的背景。 参数: pDC 指向当前要绘制的控件的DC指针。 PWnd 指向当前要绘制的控件 NCtlColor 指定了控件的类型: · CTLCOLOR_BTN 按钮控件 · CTLCOLOR_DLG 对话框 · CTLCOLOR_EDIT 编辑控件 · CTLCOLOR_LISTBOX 列表框控件 · CTLCOLOR_MSGBOX 消息框 · CTLCOLOR_SCROLLBAR 滚动条控件 · CTLCOLOR_STATIC 静态控件该函数的返回值是个画刷句柄,用于绘制指定控件的背景颜色。
控件绘制流程
当一个子控件将要被绘制时,它都会向它的父窗口(通常是对话框)发送一个WM_CTLCOLOR来准备一个设备上下文,以便使用正确的颜色来绘制该控件。如果想要改变控件上的文本颜色,可以在改函数中调用CDC类中的SetText函数来实现,改变字体背景颜色使用SetBKColor来实现,对应对话框对象来说,由于它是父窗口,会有多个子控件向它请求颜色设置,因此OnCtlColor函数会多次被调用。
在改变控件的背景颜色之前,我们需要先完成对话框的创建,然后在为创建的对话框添加类,后续的OnCtlColor函数就在这个类中响应,该函数的默认实现如下:
HBRUSH CDrawMainDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); //如果默认的不是所需画笔,则返回另一个画笔 return hbr; }对应画刷对象转化为画刷句柄的过程分析“operator Hbrush”,我们在对话框类中添加私有类型的成员变量:m_brush,在构造函数中为其初始化为蓝色画刷,这个画刷就是我们自己定义的,代码如下:
m_brush.CreateSolidBrush(RGB(0,0,255))
改变整个对话框的及其子控件的背景颜色
代码如下:
HBRUSH CDrawMainDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); //将hbr替换为我们自定义的画刷 return m_brush; }
运行效果:
改变某个控件的背景或文本颜色
如果我们只想改变某一类或者某个控件背景颜色的话,我们可以通过判断OnCtlColor响应函数中的第三个参数nCtlColor来判断当前的控件类型;若想修改某个具体的控件背景颜色和文本颜色,我们可以通过pWnd所指的类对象成员函数GetDlgCtrID来获得当前的控件ID,这里给出绘制某个具体控件的ID背景颜色和字体颜色,代码如下:
HBRUSH CDrawMainDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); int nCtrlID = pWnd->GetDlgCtrlID(); switch (nCtrlID) { //静态文本控件 case IDC_STATIC_TEST: pDC->SetTextColor(RGB(255,0,0)); //红色字体 pDC->SetBkMode(TRANSPARENT); //透明字体背景 hbr = m_brush; //蓝色控件背景 break; //编辑框控件 case IDC_EDIT: pDC->SetBkColor(RGB(0,255,0)); //绿色字体背景 break; //单选框控件 case IDC_RADIO_MATH: pDC->SetTextColor(RGB(0,255,0)); //绿色字体 hbr = (HBRUSH)GetStockObject(DKGRAY_BRUSH); //蓝色控件背景 break; //复选框控件 case IDC_CHECK_YES: pDC->SetTextColor(RGB(0,0,255)); //蓝色字体颜色 pDC->SetBkColor(RGB(0,255,255)); //天蓝色字体背景 break; case IDOK: pDC->SetTextColor(RGB(0,255,255)); //天蓝色字体 hbr = m_brush; //蓝色控件背景 break; default: break; } // 如果默认的不是所需画笔,则返回另一个画笔 return hbr; }运行效果:
改变按压式的Button控件的背景颜色和字体颜色
我们发现对应按压式的button按钮,是不起作用的,而对于Radio Button可以起作用。如果我们想修改按钮式的button按钮外观,我们需要使用CButton类的一个成员函数DrawItem,该函数声明如下:
virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );参数:
lpDrawItemStruct 指向结构DRAWITEMSTRUCT的一个长指针,该结构中记录了要绘制的项的信息以及绘制的风格。
我们可以继承CButton类定义一个我们自己的类,在自定义类中需要重写DrawItem函数。通过DrawItem函数我们就可以绘制自定义按钮,
自定义的按钮的风格需要设置为BS_OWNERDRAW才能生效。
使用步骤:
1.设置该Button控件的Owner draw选项,使之具备BS_OWNERDRAW风格。
2.将Button控件关联一个成员变量,类型为自定义的类。
3.可以在对话框的OnInitDialg函数中初始化成员变量,使之具备想要的外观。
我们将Button按钮关联为CButtonST类,并在该button未激活时将其设置成红色背景和蓝色字体颜色,该类在网络上可以找的类,具体设置代码如下:
BOOL CDrawMainDlg::OnInitDialog() { CDialog::OnInitDialog(); //编辑的显示字体 m_Edit.SetWindowText("Hello World!"); //按钮初始化 m_btnST.SetInactiveFgColor(RGB(0,0,255), TRUE); m_btnST.SetInactiveBgColor(RGB(255,0,0), TRUE); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE }运行效果:
对于部分的控件类型,使用MFC的消息反射技术,更加简单,关于消息反射的学习,在其他博文介绍,关于控件自绘4种技术和应用场景分析,参考“4种控件自绘技术分析”