參考文章:白喬原創: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(...)
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;
- }
// //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;
- }
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; }
說明二
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));
- }
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;
- }
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;
- }
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()
from:http://blog.csdn.net/wangyao1052/article/details/8070393