CComboBox在实际使用中需要改变列表中某项的背景色,文本的颜色等等,这些可以通过对CComboBox进行自绘进行实现,实现效果如下图所示。本文简单的描述了这个过程。
在对话框中拖入一个CComboBox控件,设置其属性:
这里特别强调下Has Strings,这是针对自绘CComboBox控件设置的,如果自绘控件具有Has Strings属性,那么控件本身就可以维护一个内存和指针列表,这样程序就可以使用GetText方法(对CComboBox而言,准确的说是GetLBText方法)获取特定项的字符串;否则,列表中项的字符串在 lpDrawItemStruct->itemData中(这个结构体为DrawItem函数的形参)。
CComboBox自绘的实现是通过DrawItem()函数来完成的,当一个自绘的CComboBox外观发生变化时,框架会自动自动调用DrawItem()函数,这个函数的参数lpDrawItemStruct 为LPDRAWITEMSTRUCT结构体指针,包含了所要绘制的控件的DC、ID、列表项的序号、项的状态、项的动作、重绘范围等等信息,可以参见MSDN.
自绘控件需要从CComboBox派生处一个类,在类中改写DrawItem()函数。头文件为:
class CCustomComboBox :public CComboBox
{
DECLARE_DYNAMIC(CCustomComboBox)
public:
CCustomComboBox();
~CCustomComboBox();
//protected:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
};
实现文件为:
IMPLEMENT_DYNAMIC(CCustomComboBox, CComboBox)
CCustomComboBox::CCustomComboBox()
:CComboBox()
{}
CCustomComboBox::~CCustomComboBox()
{}
void CCustomComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
COLORREF crOldTextColor = dc.GetTextColor(); //完成绘图后恢复DC里的值
COLORREF crOldBkColor = dc.GetBkColor();
// 选中一项,包括重绘编辑框和下拉列表某一项
if (lpDrawItemStruct->itemState & ODS_SELECTED)
{
dc.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
dc.SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
dc.FillSolidRect(&lpDrawItemStruct->rcItem, ::GetSysColor(COLOR_HIGHLIGHT));
}
// 控件获取焦点
else if (lpDrawItemStruct->itemState & ODS_FOCUS)
{
dc.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
dc.SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
dc.FillSolidRect(&lpDrawItemStruct->rcItem, ::GetSysColor(COLOR_HIGHLIGHT));
}
else
{
//绘制常态下的编辑框
if (lpDrawItemStruct->itemAction & ODA_DRAWENTIRE &&
lpDrawItemStruct->itemState & ODS_COMBOBOXEDIT)
dc.FillSolidRect(&lpDrawItemStruct->rcItem, ::GetSysColor(COLOR_BTNSHADOW));
//绘制常态下的下拉列表
else
{
int iCount = GetCount();
if (iCount && lpDrawItemStruct->itemID == iCount - 1) //绘制最后一项
{
CRect rect = lpDrawItemStruct->rcItem;
//dc.FillSolidRect(&lpDrawItemStruct->rcItem, ::GetSysColor(COLOR_3DFACE)); //获取对话框背景颜色
dc.FillSolidRect(&lpDrawItemStruct->rcItem, RGB(0,255,0)); //为了表示清楚,此处显示红色
dc.DrawEdge(&lpDrawItemStruct->rcItem, EDGE_BUMP, BF_RECT); //绘制一个矩形框
}
else //绘制除最后一项的其他项
dc.FillSolidRect(&lpDrawItemStruct->rcItem, crOldBkColor);
}
}
CString sItem;
//最后一项被选中后不在编辑框中绘制文本
if (lpDrawItemStruct->itemID != -1 &&
!(lpDrawItemStruct->itemID == GetCount() - 1 && lpDrawItemStruct->itemState & ODS_COMBOBOXEDIT))
{
GetLBText(lpDrawItemStruct->itemID, sItem);
dc.DrawText(sItem, sItem.GetLength(), &lpDrawItemStruct->rcItem,
DT_LEFT | DT_SINGLELINE | DT_VCENTER);
}
dc.SetTextColor(crOldTextColor);
dc.SetBkColor(crOldBkColor);
dc.Detach();
}
在Dialog类中的头文件加入
private:
CCustomComboBox m_wndCmbCustom;
在Dialog类的实现文件中加入
m_wndCmbCustom.InsertString(0, _T("hello"));
m_wndCmbCustom.InsertString(1, _T("he"));
m_wndCmbCustom.InsertString(1, _T("h"));
即可实现上述效果。