讓ListBox控件每一行顯示不同的顏色

最近用MFC做個小項目,想要讓ListBox中的每一行都根據自定義的顏色來顯示不同的顏色。剛開始把MFC想的太簡單了,拖了一個ListBox控件然後綁定了一個變量m_ListBox。

在主對話框的OnInitDialog()函數中我調用了下面的代碼

m_ListBox.AddString(_T("這是一個小測試!"));
m_ListBox.SetItemData(0,RGB(0,0,255));
運行後發現顯示的仍是默認的黑色。

後來查閱相關資料,才發現微軟將這些控件的字體和顏色等屬性都是設置爲默認的,普通的屬性設置函數根本沒用。要想在ListBox或者ListCtrl等控件中繪製你想要的圖形或者設置你想要的屬性,那麼必須採用自繪的方式。

界面方面的編程有時就是一層窗戶紙,捅破了就好。下面是實現的具體過程:

1.拖一個ListBox控件設置一下屬性。其中Owner draw屬性要設置成Variable,Has strings要勾選


2.自定義一個派生自CListBox的類CColorListBox。重載下面兩個虛函數

virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
然後定義一個接口用來讓我們調用,根據傳入的字符串和RGB值讓ListBox的每一行根據我們自定義的顏色來顯示

public:
	int AddString(LPCTSTR lpszItem, COLORREF itemColor = RGB(255,0,0));

下面是上面3個函數的具體定義


////////////////////////////////////////////////////////

/********************************************************************/
/*																	*/
/* Function name : AddString										*/		
/* Description   : Add string to the listbox and save color info.	*/
/*																	*/
/********************************************************************/
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;
}


/********************************************************************/
/*																	*/
/* Function name : DrawItem											*/		
/* Description   : Called by the framework when a visual aspect of	*/
/*				   an owner-draw list box changes.					*/
/*																	*/
/********************************************************************/
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);	
}

3.現在我們可以測試一下。拖一個ListBox控件,然後定義一個CColorListBox 類型的變量m_ListBox。你可以直接在下面所對應的位置手動添加如下代碼,也可以通過MFC ClassWizard自動添加。

在主對話框頭文件中頭文件中添加

// Dialog Data
	//{{AFX_DATA(CLogSystemTestDlg)
         ........
	CColorListBox	m_ListBox;
	//}}AFX_DATA

在主對話框的代碼文件中的DoDataExchange()函數中添加代碼

DDX_Control(pDX, IDC_LIST1, m_ListBox);
目的是將變量m_ListBox和IDC_LIST1標識的列表控件綁定,具體代碼如下

void CTestDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CLogSystemTestDlg)
	DDX_Control(pDX, IDC_LIST1, m_ListBox);
	//}}AFX_DATA_MAP
}

在主對話框的代碼文件中的OnInitDIalog()函數中添加測試代碼

BOOL CLogSystemTestDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	...........
	// TODO: Add extra initialization here
	m_ListBox.AddString("空山新雨後",RGB(255,0,0));
	m_ListBox.AddString("天氣晚來秋",RGB(0,255,0));
	m_ListBox.AddString("明月鬆間照",RGB(0,0,255));
	m_ListBox.AddString("清泉石上流",RGB(255,0,255));
	return TRUE;  // return TRUE  unless you set the focus to a control
}


編譯運行後效果如下所示


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章