【自绘ListBox】带图标的ListBox

本文介绍了一个自绘列表框的实现方法,包括如何在列表框中显示图标,并提供了详细的代码示例。通过设置不同的属性,可以灵活地控制列表框的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

示例图片

这里写图片描述

源码下载

源码下载
示例程序下载

使用说明

提供的接口如下:

void SetImageList(CImageList* pImageList);
CImageList* GetImageList() const;
int GetItemImage(int nIndex);
int SetItemImage(int nIndex, int nImageIndex, BOOL bRepaint = TRUE);

int AddString(LPCTSTR lpszString, int nImageIndex = -1);
int DeleteString(UINT nIndex);
int InsertString(int nIndex, LPCTSTR lpszString, int nImageIndex);
void ResetContent();

DWORD_PTR GetItemData(int nIndex) const;
int SetItemData(int nIndex, DWORD_PTR dwItemData);
void* GetItemDataPtr(int nIndex) const;
int SetItemDataPtr(int nIndex, void* pData);

使用方法:

Owner Draw — Variable
Has Strings — True

CListBoxXI m_listbox1;
CImageList m_imglist1;
m_imglist1.Create(32, 32, ILC_COLOR32 | ILC_MASK, 2, 1);
m_imglist1.Add(AfxGetApp()->LoadIcon(IDI_ICON1));
m_imglist1.Add(AfxGetApp()->LoadIcon(IDI_ICON2));

m_listbox1.SetImageList(&m_imglist1);
m_listbox1.AddString("456", 1);
m_listbox1.AddString("123", 0);
m_listbox1.AddString("hello kitty", 0);

注意事项:

自绘也就是在DrawItem及MeasureItem中实现。

源码

[ListBoxXI.h]

#pragma once

// CListBoxXI

class CListBoxXI : public CListBox
{
    DECLARE_DYNAMIC(CListBoxXI)

public:
    CListBoxXI();
    virtual ~CListBoxXI();

    void SetImageList(CImageList* pImageList);
    CImageList* GetImageList() const;
    int GetItemImage(int nIndex);
    int SetItemImage(int nIndex, int nImageIndex, BOOL bRepaint = TRUE);

    int AddString(LPCTSTR lpszString, int nImageIndex = -1);
    int DeleteString(UINT nIndex);
    int InsertString(int nIndex, LPCTSTR lpszString, int nImageIndex);
    void ResetContent();

    DWORD_PTR GetItemData(int nIndex) const;
    int SetItemData(int nIndex, DWORD_PTR dwItemData);
    void* GetItemDataPtr(int nIndex) const;
    int SetItemDataPtr(int nIndex, void* pData);

protected:
    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);

    DECLARE_MESSAGE_MAP()

private:
    // 关联的CImageList
    CImageList *m_pImageList;
    CSize      m_imageSize;

    // 每项的关联数据
    struct LBDataXI
    {
        // 图像序号,如果为-1,则表示无图像
        int iImageIndex;

        // 关联数据的指针
        LPVOID pData;

        LBDataXI()
        {
            iImageIndex = -1;
            pData = NULL;
        }
    };

    // 删除关联数据
    void DeleteItemData(int nIndex);
};

[ListBoxXI.cpp]

/**********************************************************
 ListBoxXI.cpp : implementation file
 Written by WangYao (wangyao1052@163.com)
 Version: V1.0 2014-06-07
**********************************************************/

#include "stdafx.h"
#include "ListBoxXI.h"

#define LBXI_CX_BORDER   2
#define LBXI_CY_BORDER   2

// CListBoxXI

IMPLEMENT_DYNAMIC(CListBoxXI, CListBox)

CListBoxXI::CListBoxXI()
{
    m_pImageList = NULL;
    m_imageSize.cx = 0;
    m_imageSize.cy = 0;
}

CListBoxXI::~CListBoxXI()
{
}

//---------------------------------------------------------
// 函数: SetImageList
// 功能: 设置关联的ImageList
// 参数: 
//       pImageList --- ImageList的指针
// 返回: 无
//---------------------------------------------------------
void CListBoxXI::SetImageList(CImageList* pImageList)
{
    m_pImageList = pImageList;
    if (m_pImageList)
    {
        int cx;
        int cy;
        ImageList_GetIconSize(*m_pImageList, &cx, &cy);
        m_imageSize.cx = cx;
        m_imageSize.cy = cy;
    }
    else
    {
        m_imageSize.cx = 0;
        m_imageSize.cy = 0;
    }

    Invalidate();
}

//---------------------------------------------------------
// 函数: GetImageList
// 功能: 获取关联ImageList的指针
// 参数: 无
// 返回: 关联ImageList的指针,若没有关联ImageList返回NULL
//---------------------------------------------------------
CImageList* CListBoxXI::GetImageList() const
{
    return m_pImageList;
}

//---------------------------------------------------------
// 函数: GetItemImage
// 功能: 获取项的图片索引
// 参数: 
//       nIndex  --- 项索引(以0为起点)
// 返回:
//       以0为起始的图片索引序号
//       若存在错误,如nIndex超出范围,返回-1
//       若项没有关联图片,返回-1
//---------------------------------------------------------
int CListBoxXI::GetItemImage(int nIndex)
{
    LBDataXI* pLBData = (LBDataXI*)CListBox::GetItemData(nIndex);
    if (pLBData == (LBDataXI*)LB_ERR || pLBData == NULL)
    {
        return -1;
    }

    return pLBData->iImageIndex;
}

//---------------------------------------------------------
// 函数: SetItemImage
// 功能: 设置项的图片索引
// 参数: 
//       nIndex      --- 项索引(以0为起点)
//       nImageIndex --- 图片索引(以0为起点)
//       bRepaint    --- 是否重绘
// 返回:
//       成功返回0,失败返回-1
//---------------------------------------------------------
int CListBoxXI::SetItemImage(int nIndex, int nImageIndex, BOOL bRepaint)
{
    LBDataXI* pLBData = (LBDataXI*)CListBox::GetItemData(nIndex);
    if (pLBData == (LBDataXI*)LB_ERR || pLBData == NULL)
    {
        return -1;
    }
    pLBData->iImageIndex = nImageIndex;

    if (bRepaint)
    {
        Invalidate();
    }

    return 0;
}

//---------------------------------------------------------
// 函数: AddString
// 功能: 添加项
// 参数: lpszString  --- 字符串指针
//        nImageIndex --- 图片索引(以0为起点)
// 返回: 新增项的索引值
//        失败则返回LB_ERR或LB_ERRSPACE
//---------------------------------------------------------
int CListBoxXI::AddString(LPCTSTR lpszString, int nImageIndex)
{
    int nIndex = CListBox::AddString(lpszString);

    if (nIndex != LB_ERR && nIndex != LB_ERRSPACE)
    {
        LBDataXI *pData = new LBDataXI();
        pData->iImageIndex = nImageIndex;
        pData->pData = NULL;
        CListBox::SetItemData(nIndex, (DWORD_PTR)pData);
    }

    return nIndex;
}

//---------------------------------------------------------
// 函数: InsertString
// 功能: 在指定位置插入项
// 参数: 
//       nIndex      --- 指定位置
//       lpszString  --- 字符串指针
//       nImageIndex --- 图片索引(以0为起点)
// 返回: 
//       插入项索引值
//       失败则返回LB_ERR或LB_ERRSPACE
//---------------------------------------------------------
int CListBoxXI::InsertString(int nIndex, LPCTSTR lpszString, int nImageIndex)
{
    int nRet = CListBox::InsertString(nIndex, lpszString);
    if (nRet != LB_ERR && nRet != LB_ERRSPACE)
    {
        LBDataXI *pData = new LBDataXI();
        pData->iImageIndex = nImageIndex;
        pData->pData = NULL;
        CListBox::SetItemData(nIndex, (DWORD_PTR)pData);
    }

    return nRet;
}

//---------------------------------------------------------
// 函数: DeleteString
// 功能: 删除项
// 参数: 
//       nIndex  --- 索引
// 返回: 
//       成功则返回当前还剩的项数
//       失败则返回LB_ERR
//---------------------------------------------------------
int CListBoxXI::DeleteString(UINT nIndex)
{
    DeleteItemData(nIndex);

    return CListBox::DeleteString(nIndex);
}

//---------------------------------------------------------
// 函数: ResetContent
// 功能: 清空内容
//---------------------------------------------------------
void CListBoxXI::ResetContent()
{
    int nCnt = CListBox::GetCount();
    for (int i = 0; i < nCnt; ++i)
    {
        DeleteItemData(i);
    }

    CListBox::ResetContent();
}

//---------------------------------------------------------
// 函数: GetItemData
// 功能: 获取项关联的数据
// 参数:
//       nIndex --- 索引
// 返回:
//       关联的数据,失败则返回LB_ERR
//---------------------------------------------------------
DWORD_PTR CListBoxXI::GetItemData(int nIndex) const
{
    LBDataXI* pLBData = (LBDataXI*)CListBox::GetItemData(nIndex);
    if (pLBData == (LBDataXI*)LB_ERR || pLBData == NULL)
    {
        return LB_ERR;
    }

    return (DWORD_PTR)pLBData->pData;
}

//---------------------------------------------------------
// 函数: SetItemData
// 功能: 设置项关联的数据
// 参数:
//       nIndex     --- 索引
//       dwItemData --- 关联的数据 
// 返回:
//       成功返回LB_OKAY, 失败返回LB_ERR
//---------------------------------------------------------
int CListBoxXI::SetItemData(int nIndex, DWORD_PTR dwItemData)
{
    LBDataXI* pLBData = (LBDataXI*)CListBox::GetItemData(nIndex);
    if (pLBData == (LBDataXI*)LB_ERR || pLBData == NULL)
    {
        return LB_ERR;
    }

    pLBData->pData = (LPVOID)dwItemData;
    return LB_OKAY;
}

//---------------------------------------------------------
// 函数: GetItemDataPtr
// 功能: 获取项关联的数据
// 参数:
//       nIndex --- 索引
// 返回:
//       关联的数据,失败则返回LB_ERR
//---------------------------------------------------------
void* CListBoxXI::GetItemDataPtr(int nIndex) const
{
    LBDataXI* pLBData = (LBDataXI*)CListBox::GetItemDataPtr(nIndex);
    if (pLBData == (LBDataXI*)LB_ERR || pLBData == NULL)
    {
        return (void*)LB_ERR;
    }

    return pLBData->pData;
}

//---------------------------------------------------------
// 函数: SetItemDataPtr
// 功能: 设置项关联的数据
// 参数:
//       nIndex --- 索引
//       pData  --- 关联的数据
// 返回:
//       成功返回LB_OKAY, 失败则返回LB_ERR
//---------------------------------------------------------
int CListBoxXI::SetItemDataPtr(int nIndex, void* pData)
{
    LBDataXI* pLBData = (LBDataXI*)CListBox::GetItemDataPtr(nIndex);
    if (pLBData == (LBDataXI*)LB_ERR || pLBData == NULL)
    {
        return LB_ERR;
    }

    pLBData->pData = pData;
    return LB_OKAY;
}

void CListBoxXI::DeleteItemData(int nIndex)
{
    LBDataXI* pLBData = (LBDataXI*)CListBox::GetItemData(nIndex);
    if (pLBData != (LBDataXI*)LB_ERR)
    {
        delete pLBData;
        CListBox::SetItemData(nIndex, (DWORD_PTR)NULL);
    }
}

void CListBoxXI::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    pDC->SetBkMode(TRANSPARENT);
    RECT& rcItem = lpDrawItemStruct->rcItem;

    CString cstrItemText;
    CListBox::GetText(lpDrawItemStruct->itemID, cstrItemText);

    LBDataXI* pData = (LBDataXI*)CListBox::GetItemDataPtr(lpDrawItemStruct->itemID);
    if (NULL == pData)
    {
        return;
    }

    // 是否处于选中状态
    BOOL bIsSelected = (lpDrawItemStruct->itemAction | ODA_SELECT) 
        && (lpDrawItemStruct->itemState & ODS_SELECTED);

    // 是否处于焦点状态
    BOOL bIsFocused = (lpDrawItemStruct->itemAction | ODA_FOCUS) 
        && (lpDrawItemStruct->itemState & ODS_FOCUS);

    // 绘制背景
    if (bIsSelected)
    {
        COLORREF oldColor = pDC->GetBkColor();
        pDC->FillSolidRect(&rcItem, ::GetSysColor(COLOR_HIGHLIGHT));
        pDC->SetBkColor(oldColor);
    }
    else
    {
        pDC->FillSolidRect(&rcItem, pDC->GetBkColor());
    }

    // 绘制ICON
    CRect rcIcon(rcItem.left, rcItem.top, rcItem.left, rcItem.top);
    if (m_pImageList)
    {
        HICON hIcon = m_pImageList->ExtractIcon(pData->iImageIndex);
        if (hIcon)
        {
            rcIcon.right = rcItem.left + m_imageSize.cx + 2 * LBXI_CX_BORDER;
            rcIcon.bottom = rcItem.top + m_imageSize.cy + 2 * LBXI_CY_BORDER;

            CPoint pos(rcIcon.left + LBXI_CX_BORDER, rcIcon.top + LBXI_CY_BORDER);
            pDC->DrawState(pos, m_imageSize, hIcon, DSS_NORMAL, (CBrush*)NULL);
            ::DestroyIcon(hIcon);
        }
    }

    // 绘制Text
    if (bIsSelected)
    {
        pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
    }
    else
    {
        pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
    }
    CRect rcText(rcItem);
    rcText.left = rcIcon.right;
    rcText.top = rcIcon.top;
    pDC->DrawText(cstrItemText, rcText, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_WORDBREAK);
}

void CListBoxXI::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
    CDC *pDC = GetDC();
    LPCTSTR lpszText = (LPCTSTR)lpMeasureItemStruct->itemData;
    CSize szText = pDC->GetTextExtent(lpszText);
    ReleaseDC(pDC);

    lpMeasureItemStruct->itemHeight = 
        szText.cy > m_imageSize.cy + 2 * LBXI_CY_BORDER ? szText.cy :  m_imageSize.cy + 2 * LBXI_CY_BORDER;
}

BEGIN_MESSAGE_MAP(CListBoxXI, CListBox)
END_MESSAGE_MAP()

// CListBoxXI message handlers
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值