[英]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_OWNERDRAWFIXED
或CBS_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.