【自绘ListBox之一】带Icon的ListBox控件

参考:
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();
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值