转载自: wangyao1052 的WM_CTLCOLOR消息
参考文章:白乔原创:VC之美化界面篇
在每个控件开始绘制之前,都会向其父窗口发送WM_CTLCOLOR
通告消息,在该消息的处理函数中,可以设置控件显示文本的前景色、背景色以及字体。该消息处理函数还要求返回一个画刷的句柄,用于在控件具体的绘制之前擦除其客户区。
WM_CTLCOLOR
映射消息处理函数为afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)。
常用代码:
pDC->SetTextColor(RGB(255, 0, 0)); //设置文本前景色
pDC->SetBkColor(RGB(255, 255, 255)); //设置文本背景色
pDC->SetBkMode(TRANSPARENT); //TRANSPARENT或OPAQUE
pDC->SelectObject(...)
简单示例如下:
//
//m_font1与m_font2为CTestDlg的成员,类型为CFont
//
BOOL CTestDlg::OnInitDialog()
{
......
// TODO: Add extra initialization here
m_font1.CreatePointFont(120, TEXT("Impact"));
m_font2.CreatePointFont(120, TEXT("Arial"));
......
}
HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: Change any attributes of the DC here
if (nCtlColor == CTLCOLOR_STATIC)
{
switch (pWnd->GetDlgCtrlID())
{
case IDC_STATIC_1:
pDC->SetTextColor(RGB(255, 0, 0));
pDC->SetBkColor(RGB(255, 255, 255));
pDC->SetBkMode(TRANSPARENT);
pDC->SelectObject(&m_font1);
return (HBRUSH)::GetStockObject(BLACK_BRUSH);
break;
case IDC_STATIC_2:
pDC->SetTextColor(RGB(255, 255, 0));
pDC->SetBkColor(RGB(255, 255, 255));
pDC->SelectObject(&m_font2);
return (HBRUSH)::GetStockObject(BLACK_BRUSH);
break;
default:
break;
}
}
// TODO: Return a different brush if the default is not desired
return hbr;
}
说明一
OnCtlColor
中的nCtlColor
可为:
CTLCOLOR_BTN //Button control
CTLCOLOR_DLG //Dialog box
CTLCOLOR_EDIT //Edit control
CTLCOLOR_LISTBOX //List-box control
CTLCOLOR_MSGBOX //Message box
CTLCOLOR_SCROLLBAR //Scroll-bar control
CTLCOLOR_STATIC //Static control
可见,WM_CTLCOLOR
可作用于按钮控件CButton
、编辑框控件CEdit
、ListBox
控件、Static
控件、滚动条控件,也可作用于对话框本身。
注意:前面讲WM_CTLCOLOR
为通告消息,也即是子控件发送给父窗口的,但对于对话框本身,它能收到nCtlColor
为CTLCOLOR_DLG
的WM_CTLCOLOR
消息,这是自身发给自身的,显然,这时不是通告消息。
示例:
HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: Change any attributes of the DC here
if (nCtlColor == CTLCOLOR_DLG)
return (HBRUSH)::GetStockObject(BLACK_BRUSH);
else
pDC->SetTextColor(RGB(255, 0, 0));
// TODO: Return a different brush if the default is not desired
return hbr;
}
说明2
OnCtlColor
消息里面的处理对PushButton
是不起作用的,由说明一中的示例效果也可以看出,而对CheckBox
和RadioButton
是OK的。附上CSDN给出的解释:
Buttons with the BS_PUSHBUTTON
, BS_DEFPUSHBUTTON
,or BS_PUSHLIKE
styles do not use the returned brush. Buttons with these styles are always drawn with the default system colors. Drawing push buttons requires several different brushes-face, highlight, and shadow-but the WM_CTLCOLORBTN
message allows only one brush to be returned. To provide a custom appearance for push buttons, use an owner-drawn button.
所以,对PushButton
只能将其设置为owner-drawn button
,然后响应控件通告消息WM_DRAWITEM
来处理,该消息的响应函数原型为afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
。
说明三:对ComboBox控件的应用
ComboBox
控件包含一个EditBox
,当单击展开的时候,会出现一个ListBox
列出所有的项目,注意,这时ListBox
控件的父窗口不是这个ComboBox
,而是ComboBox
的父窗口。
所以,如果要在代码中设置某个ComboBox
所显示文字的字体颜色为红色(EditBox
以及下拉ListBox
中的文字),假设该ComboBox
的ID为IDC_COMBO
,则使用如下代码将无任何作用。
if (pWnd->GetDlgCtrlID() == IDC_COMBO)
{
pDC->SetTextColor(RGB(255, 0, 0));
}
EditBox以及下拉ListBox中的文字颜色均没有改变。
以下对话框中有两个ComboBox控件m_combo1,m_combo2。现要使m_combo1中显示的文字颜色为红色,而m_combo2为默认。代码如下
HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: Change any attributes of the DC here
//对m_combo1的EditBox(该EditBox的父窗口为m_combo1)
if (nCtlColor == CTLCOLOR_EDIT
&& pWnd->GetParent()->GetDlgCtrlID() == m_combo1.GetDlgCtrlID())
{
pDC->SetTextColor(RGB(255, 0, 0));
}
//对m_combo1下拉的ListBox
if (nCtlColor == CTLCOLOR_LISTBOX
&& m_combo1.GetParent()->GetDlgCtrlID() == pWnd->GetParent()->GetDlgCtrlID())
{
//获取ListBox和m_combo1的屏幕坐标范围
RECT rectListBox;
RECT rectComboBox;
pWnd->GetWindowRect(&rectListBox);
m_combo1.GetWindowRect(&rectComboBox);
//如果该ListBox刚好在m_combo1的下面,则是单击m_combo1产生的下拉ListBox
if (rectListBox.left == rectComboBox.left
&& rectListBox.top == rectComboBox.bottom)
{
pDC->SetTextColor(RGB(255, 0, 0));
}
}
// TODO: Return a different brush if the default is not desired
return hbr;
}
更简单的办法是:利用向导新增MFC类CMyComboBox : CComboBox
,再增加WM_CTLCOLOR
消息的响应函数。(注意:ComboBox
下的EditBox
和ListBox
均会向ComboBox
窗口发送WM_CTLCOLOR
消息,如果在ComboBox
对应的消息映射表没有找到对应的处理函数,再向CComboBox
的父窗口发送WM_CTLCOLOR
消息,具体可参考文章WM_NOTIFY
消息流程实例分析)
BEGIN_MESSAGE_MAP(CMyComboBox, CComboBox)
ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
HBRUSH CMyComboBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: Change any attributes of the DC here
pDC->SetTextColor(RGB(255, 255, 0));
// TODO: Return a different brush if the default is not desired
return hbr;
}
pDC->SetTextColor(RGB(255, 255, 0));
一句代码就可以实现上面的功能。
说明四
WM_CTLCOLOR
为通告消息,所以也可以在反射消息中处理。
ON_WM_CTLCOLOR_REFLECT()