参考:
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();
}