最近用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 boxint nIndex = CListBox::AddString(lpszItem); // save color dataif (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 dataCOLORREF 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 TRANSPARENTint 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));elseclrOld = pDC->SetTextColor(clrNew);// get item textGetText(lpDrawItemStruct->itemID, sText);CRect rect = lpDrawItemStruct->rcItem;// text formatUINT nFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER;if (GetStyle() & LBS_USETABSTOPS)nFormat |= DT_EXPANDTABS;// draw the textpDC->DrawText(sText, -1, &rect, nFormat);// restore old valuespDC->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) ........CColorListBoxm_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 herem_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}
編譯運行後效果如下所示