WM_CTLCOLOR消息重载

转载自: 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、编辑框控件CEditListBox控件、Static控件、滚动条控件,也可作用于对话框本身。
注意:前面讲WM_CTLCOLOR为通告消息,也即是子控件发送给父窗口的,但对于对话框本身,它能收到nCtlColorCTLCOLOR_DLGWM_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;  
}  

pic 2


说明2
OnCtlColor消息里面的处理对PushButton是不起作用的,由说明一中的示例效果也可以看出,而对CheckBoxRadioButton是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下的EditBoxListBox均会向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()


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值