MFC ListBox控制元件設定字型顏色
阿新 • • 發佈:2018-12-12
描述
最近的專案中需要用到 MFC 的列表控制元件,列表控制元件中需要動態插入產品不同的測試狀態,產品的不同狀態下的測試結果分為 PASS 和 FAIL 兩種情況,這兩種測試結果插入的狀態字串顏色分別呈現為綠色和紅色。並且雙擊狀態 Item,繪製出對應狀態下的測試結果曲線。
需要解決的問題
- MFC 自帶的 ListBox 控制元件無法設定 Item 中的顏色
- 捕獲控制元件中的 Item 雙擊事件
方案
設定 Item 顏色
ListBox 無法直接設定字型顏色,因此需要自己實現對字型重繪功能。建立一個繼承 ListBox 的類
CColorListBox,重寫ListBox 中以下虛擬函式
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
以及過載函式
int AddString(LPCTSTR lpszItem, COLORREF itemColor);
實現如下:
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到指定視窗進行響應。
回撥函式原型:
//回撥函式:雙擊列表中的姿態,圖表進行響應切換,引數為自定義的測試結果結構體
typedef void(CALLBACK DBCLICKBOXCALLBACK) (ANTRes res);
typedef DBCLICKBOXCALLBACK FAR *LPDBCLICKBOXCALLBACK;
回撥函式註冊
//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 控制元件字型與字號
CFont m_font;
m_font.CreatePointFont(580, _T("宋體"));
GetDlgItem(IDC_STATIC_RESULT_TOTAL)->SetFont(&m_font);