CComboBox自绘控件的简单实现

CComboBox在实际使用中需要改变列表中某项的背景色,文本的颜色等等,这些可以通过对CComboBox进行自绘进行实现,实现效果如下图所示。本文简单的描述了这个过程。
CComboBox自绘控件的简单实现_第1张图片

1 自绘控件属性设置

在对话框中拖入一个CComboBox控件,设置其属性:

  1. type为下拉列表;
  2. Owner Draw为fixed;
  3. Has Strings为TRUE。

这里特别强调下Has Strings,这是针对自绘CComboBox控件设置的,如果自绘控件具有Has Strings属性,那么控件本身就可以维护一个内存和指针列表,这样程序就可以使用GetText方法(对CComboBox而言,准确的说是GetLBText方法)获取特定项的字符串;否则,列表中项的字符串在 lpDrawItemStruct->itemData中(这个结构体为DrawItem函数的形参)。

2 代码实现

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

即可实现上述效果。

你可能感兴趣的:(MFC,c++,c语言)