WM_CTLCOLOR消息 .


參考文章:白喬原創:VC之美化界面篇

        在每個控件開始繪制之前,都會向其父窗口發送WM_CTLCOLOR通告消息,在該消息的處理函數中,可以設置控件顯示文本的前景色、背景色以及字體。該消息處理函數還要求返回一個畫刷的句柄,用於在控件具體的繪制之前擦除其客戶區。

        WM_CTLCOLOR映射消息處理函數為afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)。
    常用代碼為:

  1. pDC->SetTextColor(RGB(255, 0, 0));    //設置文本前景色   
  2. pDC->SetBkColor(RGB(255, 255, 255));  //設置文本背景色   
  3. pDC->SetBkMode(TRANSPARENT);          //TRANSPARENT或OPAQUE   
  4. pDC->SelectObject(...)  
pDC->SetTextColor(RGB(255, 0, 0));    //設置文本前景色
pDC->SetBkColor(RGB(255, 255, 255));  //設置文本背景色
pDC->SetBkMode(TRANSPARENT);          //TRANSPARENT或OPAQUE
pDC->SelectObject(...)

        簡單示例如下:

  1. //   
  2. //m_font1與m_font2為CTestDlg的成員,類型為CFont   
  3. //   
  4. BOOL CTestDlg::OnInitDialog()  
  5. {  
  6.         ......  
  7.     // TODO: Add extra initialization here   
  8.         m_font1.CreatePointFont(120,  TEXT("Impact"));   
  9.         m_font2.CreatePointFont(120,  TEXT("Arial"));  
  10.         ......  
  11. }  
  12.   
  13. HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)  
  14. {  
  15.     HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);  
  16.   
  17.     // TODO:  Change any attributes of the DC here   
  18.     if (nCtlColor == CTLCOLOR_STATIC)  
  19.     {  
  20.         switch (pWnd->GetDlgCtrlID())  
  21.         {  
  22.         case IDC_STATIC_1:  
  23.             pDC->SetTextColor(RGB(255, 0, 0));  
  24.             pDC->SetBkColor(RGB(255, 255, 255));  
  25.             pDC->SetBkMode(TRANSPARENT);  
  26.             pDC->SelectObject(&m_font1);  
  27.             return (HBRUSH)::GetStockObject(BLACK_BRUSH);  
  28.             break;  
  29.         case IDC_STATIC_2:  
  30.             pDC->SetTextColor(RGB(255, 255, 0));  
  31.             pDC->SetBkColor(RGB(255, 255, 255));  
  32.             pDC->SelectObject(&m_font2);  
  33.             return (HBRUSH)::GetStockObject(BLACK_BRUSH);  
  34.             break;  
  35.         default:  
  36.             break;  
  37.         }  
  38.     }  
  39.   
  40.     // TODO:  Return a different brush if the default is not desired   
  41.     return hbr;  
  42. }  
//
//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消息,這是自身發給自身的,顯然,這時不是通告消息。

示例:

  1. HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)  
  2. {  
  3.     HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);  
  4.   
  5.     // TODO:  Change any attributes of the DC here   
  6.     if (nCtlColor == CTLCOLOR_DLG)  
  7.         return (HBRUSH)::GetStockObject(BLACK_BRUSH);  
  8.     else  
  9.         pDC->SetTextColor(RGB(255, 0, 0));  
  10.   
  11.     // TODO:  Return a different brush if the default is not desired   
  12.     return hbr;  
  13. }  
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,則使用如下代碼將無任何作用。
  1. if (pWnd->GetDlgCtrlID() == IDC_COMBO)  
  2. {  
  3.     pDC->SetTextColor(RGB(255, 0, 0));  
  4. }  
if (pWnd->GetDlgCtrlID() == IDC_COMBO)
{
    pDC->SetTextColor(RGB(255, 0, 0));
}
EditBox以及下拉ListBox中的文字顏色均沒有改變。
    以下對話框中有兩個ComboBox控件m_combo1,m_combo2。現要使m_combo1中顯示的文字顏色為紅色,而m_combo2為默認。代碼如下
  1. HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)  
  2. {  
  3.     HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);  
  4.   
  5.     // TODO:  Change any attributes of the DC here   
  6.   
  7.     //對m_combo1的EditBox(該EditBox的父窗口為m_combo1)   
  8.     if (nCtlColor == CTLCOLOR_EDIT  
  9.         && pWnd->GetParent()->GetDlgCtrlID() == m_combo1.GetDlgCtrlID())  
  10.     {  
  11.         pDC->SetTextColor(RGB(255, 0, 0));  
  12.     }  
  13.   
  14.     //對m_combo1下拉的ListBox   
  15.     if (nCtlColor == CTLCOLOR_LISTBOX  
  16.         && m_combo1.GetParent()->GetDlgCtrlID() == pWnd->GetParent()->GetDlgCtrlID())  
  17.     {  
  18.         //獲取ListBox和m_combo1的屏幕坐標范圍   
  19.         RECT rectListBox;  
  20.         RECT rectComboBox;  
  21.         pWnd->GetWindowRect(&rectListBox);  
  22.         m_combo1.GetWindowRect(&rectComboBox);  
  23.         //如果該ListBox剛好在m_combo1的下面,則是單擊m_combo1產生的下拉ListBox   
  24.         if (rectListBox.left == rectComboBox.left  
  25.             && rectListBox.top == rectComboBox.bottom)  
  26.         {  
  27.             pDC->SetTextColor(RGB(255, 0, 0));  
  28.         }  
  29.     }  
  30.   
  31.     // TODO:  Return a different brush if the default is not desired   
  32.     return hbr;  
  33. }  
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消息流程實例分析
  1. BEGIN_MESSAGE_MAP(CMyComboBox, CComboBox)  
  2.     ON_WM_CTLCOLOR()  
  3. END_MESSAGE_MAP()  
  4.   
  5. HBRUSH CMyComboBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)  
  6. {  
  7.     HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);  
  8.   
  9.     // TODO:  Change any attributes of the DC here   
  10.     pDC->SetTextColor(RGB(255, 255, 0));  
  11.   
  12.     // TODO:  Return a different brush if the default is not desired   
  13.     return hbr;  
  14. }  
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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM