使用虚拟 CListCtrl 显示文本和位图






4.90/5 (21投票s)
包含创建虚拟列表控件的代码,该控件还会在运行时显示来自文件的位图。

引言
本文展示了一个使用列表控件执行以下操作的示例:
- 虚拟访问数据对象
- 访问大于视图中使用的典型图标的位图
- 从文件名虚拟访问位图
背景
我的公司 Rimage 生产高端 CD、DVD 和蓝光光盘制作设备。我所从事的软件专门称为 QuickDisc。它是帮助桌面用户使用拖放方式收集文件并选择在创建光盘时想要使用的选项的界面。我们的设备会自动加载光盘驱动器并使用我们开发的打印机在光盘上打印。我被分配的任务是在 QuickDisc 中添加一个功能,该功能将在列表控件中显示位图(缩略图)。
在我们的例子中,可能有成千上万个这样的位图,所以我不想一次将它们全部加载到内存中,当然也不想将它们全部托管在列表控件中。我四处寻找动态加载位图的示例,只找到了一些,所以我决定分享这个结果。代码注释详尽,一旦理解了,这些技术也相当简单。
使用代码/感兴趣的点
这只是一个示例程序,因此用户可以将任何代码剪切和粘贴到他们自己的程序中,并根据他们的特定需求进行调整。我选择使用 BMP 文件,但使用 CImage
类加载任何类型的图形(JPG、PNG 等)并在运行时将其转换为 ImageList
格式是很容易的事。虚拟列表控件的一个优点是,只有显示在屏幕上的数据才实际位于控件中。其余数据整齐地存储在数据集合或光盘上的其他地方。因此,无论显示多少项目,控件都不会变慢。
代码中感兴趣的具体项目如下所示。注意:我实际上并没有将 imagelist
用于任何除了最终位图的保留位置之外的用途。
if(m_imageList.GetSafeHandle() == NULL) {
m_imageList.Create(210, 160, ILC_COLOR24 | ILC_MASK, 8, 1);
m_cList.SetImageList(&m_imageList, LVSIL_SMALL);
m_cList.SetImageList(&m_imageList, LVSIL_NORMAL);
m_imageList.SetImageCount(1);
} CString csFilePath = _T("C:\\TestFiles");
我将列表控件中的项目数设置为我的相应数据数组中的计数。列表认为它有这么多项目,即使我从未实际加载任何内容到其中。
// This sets the count in the list without adding any items. This is very fast.
m_cList.SetItemCountEx((int)m_MyDataArray.GetCount(),
LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL);
这是主力例程。它由列表控件为它想要在屏幕上显示的每一行调用。请注意,我正在处理两个掩码,一个用于文本,另一个用于位图。
void CBMPListDlg::GetDispInfo(NMHDR *pNMHDR, LRESULT *pResult)
{
NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
//Create a pointer to the item
LV_ITEM* pItem= &(pDispInfo)->item;
//Which item number?
int nItem = pItem->iItem;
CMyDataInfo *pInfo = NULL;
if(nItem > m_MyDataArray.GetSize()-1)
return; // Just to be safe
pInfo = (CMyDataInfo *)m_MyDataArray.GetAt(nItem);
if(pInfo == NULL)
return;
//Do we need text information?
if (pItem->mask & LVIF_TEXT) {
CString csText;
//Which column?
if(pItem->iSubItem == 0)
csText = pInfo->m_csColumn1;
else if (pItem->iSubItem == 1) // Column 1
csText = pInfo->m_csColumn2;
else if (pItem->iSubItem == 2) // Column 2
csText = pInfo->m_csColumn3;
else if (pItem->iSubItem == 3) // Column 3
csText = pInfo->m_csColumn4;
//Copy the text to the LV_ITEM structure
//Maximum number of characters is in pItem->cchTextMax
lstrcpyn(pItem->pszText, csText, pItem->cchTextMax);
}
//Does the list need image information?
if( pItem->mask & LVIF_IMAGE) {
// Need to reset first item of image list to the
// correct bitmap
HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
pInfo->m_csImage,
IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
if(hBmp != NULL) {
CBitmap *cBmp = CBitmap::FromHandle(hBmp);
if(cBmp != NULL)
m_imageList.Replace(0,cBmp,NULL);
}
// Note, there is no Navigator 0.bmp so that image will
// always display blank to
// illustrate what would happen when the file is not found.
else {
CBitmap *cBmp = new CBitmap();
cBmp->LoadBitmap(IDB_BLANK);
m_imageList.Replace(0,cBmp,NULL);
delete cBmp;
}
pItem->iImage = 0; // Always use 0 since only one element
}
*pResult = 0;
}
历史
- 版本 1.0 - 2009 年 4 月 5 日