Mfc CComboBoxEx - Как изменить цвет фона - PullRequest
4 голосов
/ 07 ноября 2019

У меня есть класс, производный от CComboBoxEx, и я пытаюсь изменить цвет фона. Я думал, что он будет работать как 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;
         }

I 'мы пробовали и с OnEraseBkgnd(), и он тоже не работал.

Нужно ли создавать подкласс производного класса CComboBox и устанавливать цвет фона в этом классе?

Thx.

Ответы [ 3 ]

1 голос
/ 08 ноября 2019

Если все дело просто в изменении цвета Bk элемента управления, то вам нужно обработать сообщение 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;
}

В противном случае вы должны полностью отрисовать свой элемент управления в своемпроизводный класс со стилем CBS_OWNERDRAWFIXED или CBS_OWNERDRAWVARIABLE, который более сложный, но, возможно, возможный.

1 голос
/ 08 ноября 2019

Я удивлен, что все ответы, которые вы получили до сих пор, предполагают либо обработку WM_CTLCOLOR в родительском окне, либо использование одного из OWNERDRAW стилей.

Обработка WM_CTLCOLOR в родительском окне означает, что вам нужно будет продублировать этот код в классе каждого родительского окна, где вы будете использовать такой комбинированный список. Очевидно, что это плохое решение, если вы хотите использовать выпадающий список более одного раза.

Добавление стиля OWNERDRAW может повлиять на другие существующие элементы управления, которые вы хотите создать подклассом, и вам может потребоваться решить дополнительные проблемы. Это также далеко от единственного решения.

К счастью, есть еще один способ решить эту проблему - использовать Отражение сообщения . И все, что вам нужно сделать, это добавить запись ON_WM_CTLCOLOR_REFLECT() к карте сообщений и обработчик CtlColor.

В случае управления списком я бы сделал это так:

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);
};

MyComboBoxEx.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);
}

Вот как выглядит этот комбинированный список:

enter image description here

Если вы хотите иметь собственный цвет для границ и глифа, вам нужно самостоятельно обработать WM_PAINT.

1 голос
/ 07 ноября 2019

Проблема здесь в том, что WM_CTLCOLOR сообщения отправляются в окно parent (диалоговое окно, вероятно) вашего комбинированного элемента управления, а не в сам элемент управления;также, в случае раскрывающейся части списка со списком, это сообщение не отправляется (поскольку диалоговое окно не должно его рисовать, если элемент управления не был активирован).

Я достиг того, чего вы хотите, путем рисования владельца элемента управления, а затем (вручную) рисования каждого элемента в списке.

Сначала необходимо добавить стиль CBS_OWNERDRAWFIXED к элементу управления в.rc / .rc2 скрипт;например, для типичной комбинации:

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

Затем вам нужно добавить ON_WM_DRAWITEM() к карте сообщений для вашего диалогового класса и переопределить его 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;
}

Показанный код обрабатывает как отключенные комбинации, так и выбранные элементы в списке;Вы можете пропустить некоторые из них, если хотите упростить операцию.

Не стесняйтесь просить дальнейших объяснений и / или разъяснений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...