【自繪ListBox之一】帶Icon的ListBox控制元件
阿新 • • 發佈:2019-01-01
參考: CListBoxST原始碼 Demo源程式: CIconListBox_demo Demo程式圖片: 使用示例: 手動更改ListBox控制元件的屬性如下,因為以下特性不能通過程式碼動態修改。
m_listbox.AddString(TEXT("123"), IDI_ICON_1);
m_listbox.AddString(TEXT("456"), IDI_ICON_2);
m_listbox.AddString(TEXT("789"), IDI_ICON_1);
程式碼如下-------------------------------------------------------------------------------------------------------
CIconListBox類:
class CIconListBox : public CListBox { DECLARE_DYNAMIC(CIconListBox) struct LBDATA { HICON hIcon; int nIconHeight; int nIconWidth; }; public: CIconListBox(); virtual ~CIconListBox(); protected: DECLARE_MESSAGE_MAP() public: virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/); virtual void MeasureItem(LPMEASUREITEMSTRUCT /*lpMeasureItemStruct*/); // Interface int AddString(LPCTSTR lpszItem, int nIcon); int DeleteString(UINT nIndex); int InsertString(int nIndex, LPCTSTR lpszItem, int nIcon); void ResetContent(); private: void DeleteItemData(UINT nIndex); int m_nIconHeight; // Icon的高度,在MeasureItem函式裡會用此確定每一項的高度 int m_nOffset; // 繪製Icon與Text時,與邊框的偏距 };
一 override MeasureItem
// // 確定ListBox中每一項應繪製的高度 // void CIconListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) { // 確定Text的高度 ASSERT(lpMeasureItemStruct->CtlType == ODT_LISTBOX); LPCTSTR lpszText = (LPCTSTR) lpMeasureItemStruct->itemData; ASSERT(lpszText != NULL); CSize sz; CDC* pDC = GetDC(); sz = pDC->GetTextExtent(lpszText); ReleaseDC(pDC); // 比較Text與Icon的高度,取大者 int nItemHeight = 2*sz.cy > m_nIconHeight+m_nOffset*2 ? 2*sz.cy : m_nIconHeight+m_nOffset*2; lpMeasureItemStruct->itemHeight = nItemHeight; }
二 override DrawItem
void CIconListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// 準備工作
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
dc.SetBkMode(TRANSPARENT);
ASSERT(lpDrawItemStruct->CtlType == ODT_LISTBOX);
CString cstrText;
CListBox::GetText(lpDrawItemStruct->itemID, cstrText);
ASSERT(!cstrText.IsEmpty());
// 監測狀態
BOOL bIsSelected = (lpDrawItemStruct->itemAction | ODA_SELECT) &&
(lpDrawItemStruct->itemState & ODS_SELECTED);
BOOL bIsFocused = (lpDrawItemStruct->itemAction | ODA_FOCUS) &&
(lpDrawItemStruct->itemState & ODS_FOCUS);
// Draw背景
if (bIsSelected)
{
CBrush brushBk(::GetSysColor(COLOR_HIGHLIGHT));
dc.FillRect(&lpDrawItemStruct->rcItem, &brushBk);
}
else
{
CBrush brushBk(dc.GetBkColor());
dc.FillRect(&lpDrawItemStruct->rcItem, &brushBk);
}
// Draw icon
LBDATA *pLbData = (LBDATA*)CListBox::GetItemDataPtr(lpDrawItemStruct->itemID);
if (NULL != pLbData && (LBDATA*)-1 != pLbData
&& NULL != pLbData->hIcon)
{
UINT flag = DST_ICON;
::DrawState(lpDrawItemStruct->hDC, NULL, NULL, (LPARAM)pLbData->hIcon, NULL,
lpDrawItemStruct->rcItem.left + m_nOffset, lpDrawItemStruct->rcItem.top + m_nOffset,
pLbData->nIconWidth, pLbData->nIconHeight, flag);
}
// Draw text
if (bIsSelected)
{
dc.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
}
else
{
dc.SetTextColor(RGB(255, 0, 0));
}
CRect rcText;
rcText.left = lpDrawItemStruct->rcItem.left+ m_nOffset + pLbData->nIconWidth + m_nOffset;
rcText.top = lpDrawItemStruct->rcItem.top + m_nOffset + m_nOffset;
rcText.right = lpDrawItemStruct->rcItem.right - m_nOffset;
rcText.bottom = lpDrawItemStruct->rcItem.bottom - m_nOffset;
dc.DrawText(
cstrText,
&rcText,
DT_LEFT | DT_SINGLELINE | DT_VCENTER);
// 收尾工作
dc.Detach();
}
三 其他函式
//
// nIcon為ICON的ID
// 注意:CListBox::AddString中會呼叫MeasureItem確定加入項的高度,所以
// 先LoadImage確定ICON的高度,並賦值給類的私有變數m_nIconHeight,
// 這樣在MeasureItem中就可以用m_nIconHeight確定Icon的高度
//
int CIconListBox::AddString(LPCTSTR lpszItem, int nIcon)
{
LBDATA *pLbData = NULL;
m_nIconHeight = 0;
// 載入Icon
HICON hIcon = (HICON)::LoadImage(::GetModuleHandle(NULL), MAKEINTRESOURCE(nIcon),
IMAGE_ICON, 0, 0, 0);
if (hIcon != NULL)
{
pLbData = new LBDATA();
ICONINFO ici;
::GetIconInfo(hIcon, &ici);
BITMAP bm;
::GetObject(ici.hbmColor, sizeof(BITMAP), &bm);
::DeleteObject(ici.hbmColor);
::DeleteObject(ici.hbmMask);
pLbData->hIcon = hIcon;
pLbData->nIconHeight = bm.bmHeight;
pLbData->nIconWidth = bm.bmWidth;
m_nIconHeight = bm.bmHeight;
}
// Add string and lbdata
int nIndex = CListBox::AddString(lpszItem);
if (LB_ERR == nIndex || LB_ERRSPACE == nIndex)
{
if (NULL != pLbData)
{
delete pLbData;
::DestroyIcon(hIcon);
}
}
else
{
CListBox::SetItemDataPtr(nIndex, pLbData);
}
return nIndex;
}
int CIconListBox::InsertString(int nIndex, LPCTSTR lpszItem, int nIcon)
{
LBDATA *pLbData = NULL;
m_nIconHeight = 0;
// 載入Icon
HICON hIcon = (HICON)::LoadImage(::GetModuleHandle(NULL), MAKEINTRESOURCE(nIcon),
IMAGE_ICON, 0, 0, 0);
if (hIcon != NULL)
{
pLbData = new LBDATA();
ICONINFO ici;
::GetIconInfo(hIcon, &ici);
BITMAP bm;
::GetObject(ici.hbmColor, sizeof(BITMAP), &bm);
::DeleteObject(ici.hbmColor);
::DeleteObject(ici.hbmMask);
pLbData->hIcon = hIcon;
pLbData->nIconHeight = bm.bmHeight;
pLbData->nIconWidth = bm.bmWidth;
m_nIconHeight = bm.bmHeight;
}
// Insert string and lbdata
nIndex = CListBox::InsertString(nIndex, lpszItem);
if (LB_ERR == nIndex || LB_ERRSPACE == nIndex)
{
if (NULL != pLbData)
{
::DestroyIcon(hIcon);
delete pLbData;
}
}
else
{
CListBox::SetItemDataPtr(nIndex, pLbData);
}
return nIndex;
}
int CIconListBox::DeleteString(UINT nIndex)
{
DeleteItemData(nIndex);
return CListBox::DeleteString(nIndex);
}
void CIconListBox::DeleteItemData(UINT nIndex)
{
LBDATA *pLbData = (LBDATA*) CListBox::GetItemDataPtr(nIndex);
if ((LBDATA*)-1 != pLbData && NULL != pLbData)
{
if (pLbData->hIcon)
::DestroyIcon(pLbData->hIcon);
delete pLbData;
}
}
void CIconListBox::ResetContent()
{
int nCount = GetCount();
for (int i=0; i<nCount; ++i)
{
DeleteItemData(i);
}
CListBox::ResetContent();
}