MFC ListBox控件设置字体颜色

描述

最近的项目中须要用到 MFC 的列表控件,列表控件中须要动态插入产品不一样的测试状态,产品的不一样状态下的测试结果分为 PASS 和 FAIL 两种状况,这两种测试结果插入的状态字符串颜色分别呈现为绿色和红色。而且双击状态 Item,绘制出对应状态下的测试结果曲线。web

须要解决的问题

  • MFC 自带的 ListBox 控件没法设置 Item 中的颜色
  • 捕获控件中的 Item 双击事件

方案

设置 Item 颜色

ListBox 没法直接设置字体颜色,所以须要本身实现对字体重绘功能。建立一个继承 ListBox 的类
CColorListBox,重写ListBox 中如下虚函数svg

virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);

以及重载函数函数

int AddString(LPCTSTR lpszItem, COLORREF itemColor);

实现以下:post

void CColorListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	// Losing focus ?
	if (lpDrawItemStruct->itemID == -1)
	{
		DrawFocusRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem);
		return;
	}

	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

	COLORREF clrOld;
	CString sText;

	// get color info from item data
	COLORREF clrNew = (COLORREF)(lpDrawItemStruct->itemData);

	// item selected ?
	if ((lpDrawItemStruct->itemState & ODS_SELECTED) &&
		(lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)))
	{
		CBrush brush(::GetSysColor(COLOR_HIGHLIGHT));
		pDC->FillRect(&lpDrawItemStruct->rcItem, &brush);
	}

	// item deselected ?
	if (!(lpDrawItemStruct->itemState & ODS_SELECTED) &&
		(lpDrawItemStruct->itemAction & ODA_SELECT))
	{
		CBrush brush(::GetSysColor(COLOR_WINDOW));
		pDC->FillRect(&lpDrawItemStruct->rcItem, &brush);
	}

	// item has focus ?
	if ((lpDrawItemStruct->itemAction & ODA_FOCUS) &&
		(lpDrawItemStruct->itemState & ODS_FOCUS))
	{
		pDC->DrawFocusRect(&lpDrawItemStruct->rcItem);
	}

	// lost focus ?
	if ((lpDrawItemStruct->itemAction & ODA_FOCUS) &&
		!(lpDrawItemStruct->itemState & ODS_FOCUS))
	{
		pDC->DrawFocusRect(&lpDrawItemStruct->rcItem);
	}

	// set the background mode to TRANSPARENT
	int nBkMode = pDC->SetBkMode(TRANSPARENT);

	if (lpDrawItemStruct->itemState & ODS_SELECTED)
		clrOld = pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
	else
	if (lpDrawItemStruct->itemState & ODS_DISABLED)
		clrOld = pDC->SetTextColor(::GetSysColor(COLOR_GRAYTEXT));
	else
		clrOld = pDC->SetTextColor(clrNew);

	// get item text
	GetText(lpDrawItemStruct->itemID, sText);
	CRect rect = lpDrawItemStruct->rcItem;

	// text format
	UINT nFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER;
	if (GetStyle() & LBS_USETABSTOPS)
		nFormat |= DT_EXPANDTABS;

	// draw the text
	pDC->DrawText(sText, -1, &rect, nFormat);

	// restore old values
	pDC->SetTextColor(clrOld);
	pDC->SetBkMode(nBkMode);
}
void CColorListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENUCHECK);
}
int CColorListBox::AddString(LPCTSTR lpszItem, COLORREF itemColor)
{
	// Add the string to the list box
	int nIndex = CListBox::AddString(lpszItem);

	// save color data
	if (nIndex >= 0)
		SetItemData(nIndex, itemColor);

	return nIndex;
}

鼠标双击事件

右击工程进入类向导,选择自定义的 CColorListBox 类,添加 WM_LBUTTONDBLCLK 消息响应函数。进入响应函数便可添加相应的响应代码。测试

void CColorListBox::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值
	int nIndex = GetCurSel();//双击了哪一个 Item
	int nCount = GetCount();//获得总共的 Item 数
	if (nIndex >= 0 && nIndex < nCount)
	{
    	//回调函数,具体实现取决于给它注册的类
		m_dbClick(m_result[nIndex - 1]);
	}
	CListBox::OnLButtonDblClk(nFlags, point);
}

本项目采用回调的方式,即在建立列表时,给 CColorListBox 类注册一个双击事件的回调函数,如此能够在其余类中响应这一双击事件。固然,也能够在捕获到双击事件后,将消息post到指定窗口进行响应。字体

回调函数原型:this

//回调函数:双击列表中的姿态,图表进行响应切换,参数为自定义的测试结果结构体
typedef void(CALLBACK DBCLICKBOXCALLBACK) (ANTRes res);
typedef DBCLICKBOXCALLBACK FAR *LPDBCLICKBOXCALLBACK;

回调函数注册spa

//m_dbClick为 LPDBCLICKBOXCALLBACK 类型的成员,参数为具体实现的函数指针,在建立列表时调用该函数进行回调注册
void CColorListBox::setDbClickFunc(LPDBCLICKBOXCALLBACK DbClick)
{
	m_dbClick = DbClick;
}

调用

  • CColorListBox.h 头文件大体以下:
#include <vector>
using namespace std;

//回调函数:双击列表中的姿态,图标进行响应切换,能够设置参数
typedef void(CALLBACK DBCLICKBOXCALLBACK) ();
typedef DBCLICKBOXCALLBACK FAR *LPDBCLICKBOXCALLBACK;

class CColorListBox : public CListBox
{
public:
	CColorListBox();
	virtual ~CColorListBox();
	virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
	virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
	//重载
	int AddString(LPCTSTR lpszItem, COLORREF itemColor);
	DECLARE_MESSAGE_MAP()
	afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
public:
	void setDbClickFunc(LPDBCLICKBOXCALLBACK DbClick);
	LPDBCLICKBOXCALLBACK m_dbClick;//双击回调函数
};
  • CColorListBox.cpp 文件大体以下:
#include "CColorListBox.h"
CColorListBox::CColorListBox()
{
}
CColorListBox::~CColorListBox()
{
}
BEGIN_MESSAGE_MAP(CColorListBox, CListBox)
	ON_WM_LBUTTONDBLCLK()
END_MESSAGE_MAP()
void CColorListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	// Losing focus ?
	if (lpDrawItemStruct->itemID == -1)
	{
		DrawFocusRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem);
		return;
	}

	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

	COLORREF clrOld;
	CString sText;

	// get color info from item data
	COLORREF clrNew = (COLORREF)(lpDrawItemStruct->itemData);

	// item selected ?
	if ((lpDrawItemStruct->itemState & ODS_SELECTED) &&
		(lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)))
	{
		CBrush brush(::GetSysColor(COLOR_HIGHLIGHT));
		pDC->FillRect(&lpDrawItemStruct->rcItem, &brush);
	}

	// item deselected ?
	if (!(lpDrawItemStruct->itemState & ODS_SELECTED) &&
		(lpDrawItemStruct->itemAction & ODA_SELECT))
	{
		CBrush brush(::GetSysColor(COLOR_WINDOW));
		pDC->FillRect(&lpDrawItemStruct->rcItem, &brush);
	}

	// item has focus ?
	if ((lpDrawItemStruct->itemAction & ODA_FOCUS) &&
		(lpDrawItemStruct->itemState & ODS_FOCUS))
	{
		pDC->DrawFocusRect(&lpDrawItemStruct->rcItem);
	}

	// lost focus ?
	if ((lpDrawItemStruct->itemAction & ODA_FOCUS) &&
		!(lpDrawItemStruct->itemState & ODS_FOCUS))
	{
		pDC->DrawFocusRect(&lpDrawItemStruct->rcItem);
	}

	// set the background mode to TRANSPARENT
	int nBkMode = pDC->SetBkMode(TRANSPARENT);

	if (lpDrawItemStruct->itemState & ODS_SELECTED)
		clrOld = pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
	else
	if (lpDrawItemStruct->itemState & ODS_DISABLED)
		clrOld = pDC->SetTextColor(::GetSysColor(COLOR_GRAYTEXT));
	else
		clrOld = pDC->SetTextColor(clrNew);

	// get item text
	GetText(lpDrawItemStruct->itemID, sText);
	CRect rect = lpDrawItemStruct->rcItem;

	// text format
	UINT nFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER;
	if (GetStyle() & LBS_USETABSTOPS)
		nFormat |= DT_EXPANDTABS;

	// draw the text
	pDC->DrawText(sText, -1, &rect, nFormat);

	// restore old values
	pDC->SetTextColor(clrOld);
	pDC->SetBkMode(nBkMode);
}

void CColorListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENUCHECK);
}

int CColorListBox::AddString(LPCTSTR lpszItem, COLORREF itemColor)
{
	// Add the string to the list box
	int nIndex = CListBox::AddString(lpszItem);

	// save color data
	if (nIndex >= 0)
		SetItemData(nIndex, itemColor);

	return nIndex;
}

void CColorListBox::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值
	int nIndex = GetCurSel();
	int nCount = GetCount();
	if (nIndex >= 0 && nIndex < nCount)
	{
		m_dbClick();
	}
	CListBox::OnLButtonDblClk(nFlags, point);
}

void CColorListBox::setDbClickFunc(LPDBCLICKBOXCALLBACK DbClick)
{
	m_dbClick = DbClick;
}
  • 使用
//回调函数具体实现,必须和回调声明类型一致
static void WINAPI OnDbClickListItem()
{
	//此处实现双击事件具体须要作的事,如刷新图表
}

//建立一个 CColorListBox 类指针,注意不用时释放
CColorListBox *listBox = new CColorListBox();
listBox->Create(LBS_HASSTRINGS | LBS_OWNERDRAWFIXED | WS_HSCROLL | LBS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP, CRect(0, 0, 60, 60), this, IDC_LISTBOX + iAnt);
//为列表注册双击回调函数
listBox->setDbClickFunc(OnDbClickListItem);
//插入字符串,第二个参数为可选的颜色
listBox->AddString("所有姿态", RGB(255, 0, 0));//红色
  • 效果
    每种状态测试完将状态插入列表,并以颜色表示测试结果
    在这里插入图片描述
    双击右侧列表中的状态,刷新对应状态下的测试曲线
    在这里插入图片描述

Static 控件的背景颜色设置

界面在显示测试结果时,常常采用 Static 控件,有时候须要让结果看起来很醒目,这时也须要设置控件的背景颜色以达到醒目效果。那么顺便简单说一下 Static 控件的背景颜色与字体的设置,效果以下:
在这里插入图片描述指针

  • 实现
    进入类向导,选择 Static 控件所在的类,添加 WM_CTLCOLOR 消息响应函数。在响应函数中根据控件 ID 设置控件背景颜色。
HBRUSH CDlgControl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

	// TODO:  在此更改 DC 的任何特性
	int n = pWnd->GetDlgCtrlID();
	if (n == IDC_STATIC_RESULT_TOTAL)
	{
			pDC->SetBkColor(RGB(255, 0, 0));
			pDC->SetTextColor(RGB(0, 0, 0));
			hbr = CreateSolidBrush(RGB(255, 0, 0));
	}
	else if (n == IDC_STATIC_TIME)
	{
		pDC->SetTextColor(RGB(0, 0, 0));   //设置字体颜色
		pDC->SetBkMode(TRANSPARENT); //设置字体背景为透明
		hbr = CreateSolidBrush(RGB(255, 255, 0));//控件背景色
	}
	// TODO:  若是默认的不是所需画笔,则返回另外一个画笔
	return hbr;
}

设置 Static 控件字体与字号rest

CFont m_font;
m_font.CreatePointFont(580, _T("宋体"));
GetDlgItem(IDC_STATIC_RESULT_TOTAL)->SetFont(&m_font);