簡體   English   中英

Mfc CComboBoxEx - 如何更改背景顏色

[英]Mfc CComboBoxEx - How to change the background color

我有一個派生自 CComboBoxEx 的 class,我正在嘗試更改背景顏色。 我在想它會像 ComboBox 一樣工作(使用 SetBkColor 函數),但它不會改變背景顏色。

這是我嘗試過的:

    BEGIN_MESSAGE_MAP(CMyComboBoxEx, CComboBoxEx)   
       ON_WM_CTLCOLOR()
    END_MESSAGE_MAP()

     void CMyComboBoxEx::SetBkColor(COLORREF backgroundColor)
         {
            m_backgroundColor = backgroundColor;
            m_brBkgnd.DeleteObject();
            m_brBkgnd.CreateSolidBrush(backgroundColor);
         }    
     HBRUSH CMyComboBoxEx::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
         {
            HBRUSH brush = __super::OnCtlColor(pDC, pWnd, nCtlColor);
            pDC->SetBkColor(RGB(255,0,0));

            return brush;
         }

我也嘗試過OnEraseBkgnd() ,但也沒有用。

我是否需要對派生的 CComboBox class 進行子類化並在該 class 中設置背景顏色?

謝謝。

這里的問題是WM_CTLCOLOR消息被發送到您的組合控件的window (可能是對話框),而不是控件本身; 此外,在組合的下拉“列表框”部分的情況下,不會發送此消息(因為對話框不需要繪制它,除非控件已被激活)。

我實現您想要的方法是使控件所有者繪制,然后(手動)繪制列表中的每個項目。

首先,您需要在.rc / .rc2腳本中將CBS_OWNERDRAWFIXED樣式添加到您的控件中; 像這樣,對於一個典型的組合:

COMBOBOX  IDC_IGONG, 224, 68, 52,120,
    CBS_DROPDOWNLIST | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED | WS_VSCROLL | WS_TABSTOP

然后,您需要為您的對話框 class 將ON_WM_DRAWITEM()添加到消息 map 中,並覆蓋其OnDrawItem()成員。 請注意,當用戶操作使列表可見時,將為下拉列表中的每個項目發送一次消息:

void MyDialog::OnDrawItem(int nIDCtl, DRAWITEMSTRUCT *pDIS)
{
    switch (pDIS->CtlType) { // You can switch on the ID if it's only one combo!
    case ODT_COMBOBOX:
        DrawDropDownBox(this, nIDCtl, pDIS);
        break;
    default:
        CDialogEx::OnDrawItem(nIDCtl, pDIS);
        break;
    }
}

DrawDropDownBox()完成所有艱苦的工作:


void MyDialog::DrawDropDownBox(CWnd *box, int nID, DRAWITEMSTRUCT *pDIS)
{
    CComboBox *pCBC = dynamic_cast<CMyComboBoxEx *>(box->GetDlgItem(nID));
    if (pCBC == nullptr) return; // Skip if we can't get handle to the control
    CDC *pDC = CDC::FromHandle(pDIS->hDC);
    wchar_t buffer[4096]; // Or just char if you ain't using Unicode
    if (pCBC->GetLBText(int(pDIS->itemID), buffer) == CB_ERR) return; // Maybe called during WM_DELETEITEM
    int dcSave = pDC->SaveDC(); // Save DC state for later restoration
    CPen pen(PS_SOLID, 0, ListColor); // ListColor is COLORREF for your desired b/g
    if (pDIS->itemState & ODS_DISABLED) {
        pDC->SelectStockObject(NULL_PEN);
        pDC->SelectObject(BackBrush); // A CBrush for disabled: defined/created elsewhere
        pDC->SetBkMode(TRANSPARENT);
    }
    else {
        pDC->SelectObject(&pen);
        pDC->SelectObject(ListBrush); // A CBrush that draws your desired b/g
        pDC->SetBkMode(OPAQUE);
    }
    CRect rc(pDIS->rcItem); pDC->Rectangle(&rc); // This draws the b/g
    if (pDIS->itemState & ODS_DISABLED) {
        pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
    }
    else if (pDIS->itemState & ODS_SELECTED) { // Use Windows defaults if selected...
        pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
        pDC->SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
    }
    else {
        pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
        pDC->SetBkColor(ListColor); // Custom b/g color
    }
    unsigned format = DT_SINGLELINE | DT_VCENTER; // You desired text alignment
    pDC->DrawText(CString(buffer), rc, format);
    pDC->RestoreDC(dcSave); // Restore DC's saved state...
    pDC->Detach();          // ...then 'release it'
    return;
}

顯示的代碼處理列表中禁用的組合和選定的項目; 如果您想簡化操作,您可以跳過其中的一些。

隨時要求進一步解釋和/或澄清。

如果只是改變控件的 Bk 顏色,那么您必須在控件的父級 window 中處理WM_CTLCOLOR消息:

HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

    if (pWnd->GetDlgCtrlID() == IDC_MY_CONTROL)
    {
        pDC->SetBkColor(RGB(0, 0, 0)); //Black color
        hbr = m_hbrBlack;              //Black brush.
    }

    return hbr;
}

否則,您必須在派生的 class 中完全自己繪制控件,使用CBS_OWNERDRAWFIXEDCBS_OWNERDRAWVARIABLE樣式,這要復雜得多,但也可以。

我很驚訝到目前為止你得到的所有答案都建議在父 window 中處理WM_CTLCOLOR或使用OWNERDRAW styles 之一。

在父窗口 window 中處理WM_CTLCOLOR意味着您需要在每個父窗口的 class 中復制該代碼,您將在其中使用此類 combobox。 如果您想多次使用 combobox,這顯然是一個糟糕的解決方案。

添加OWNERDRAW樣式可能會影響您想要子類化的其他現有控件,並且您可能需要處理其他問題。 這也遠不是一個簡單的解決方案。

幸運的是,還有另一種解決方法——使用Message Reflection 您需要做的就是將ON_WM_CTLCOLOR_REFLECT()條目添加到消息 map 和CtlColor處理程序中。

在 combobox 控制的情況下,我會這樣做:

MyComboBoxEx.h

class CMyComboBoxEx : public CComboBoxEx
{
public:
    CMyComboBoxEx();
    virtual ~CMyComboBoxEx();

protected:

    CBrush m_BkBrush;

    DECLARE_MESSAGE_MAP()
public:
    afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
};

我的組合框Ex.cpp

CMyComboBoxEx::CMyComboBoxEx()
{
    m_BkBrush.CreateSolidBrush(RGB(0, 255, 0)); 
}

CMyComboBoxEx::~CMyComboBoxEx()
{
}

BEGIN_MESSAGE_MAP(CMyComboBoxEx, CComboBoxEx)
    ON_WM_CTLCOLOR_REFLECT()
    ON_WM_CTLCOLOR()
END_MESSAGE_MAP()

HBRUSH CMyComboBoxEx::CtlColor(CDC* pDC, UINT nCtlColor)
{
    pDC->SetTextColor(RGB(255, 0, 0));
    pDC->SetBkColor(RGB(0, 255, 0));
    return m_BkBrush;
}

HBRUSH CMyComboBoxEx::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    return CtlColor(pDC, nCtlColor);
}

以下是 combobox 的外觀:

在此處輸入圖像描述

如果您想為邊框和字形自定義顏色,那么您需要自己處理 WM_PAINT。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM