Introduction
This article shows an example of using a list control to do the following:
- Access data object virtually
- Access bitmaps larger than the typical icon used in views
- Access bitmaps virtually from a filename
Background
My company, Rimage, manufactures high end CD, DVD, and Blu-ray production equipment. The software I work on specifically is called QuickDisc. It is the interface that helps desktop users collect files using drag and drop and select the options that they want to use when creating discs. Our equipment automatically loads the disc drives and prints on the disc using a printer we developed. I was given the task of adding a feature to QuickDisc that would show a bitmap (thumbnail) in a list control.
In our case, there could be thousands of them so I didn't want to load them all into memory at the same time and certainly didn't want to host them all in the list control. I looked around for examples of loading bitmaps dynamically and found only a few so I decided to share this result. The code is heavily commented and the techniques are pretty easy once figured out.
Using the Code/Points of Interest
This is just an example program so users could cut and paste any of the code into their own programs and tailor to their particular needs. I chose to use BMP files, but it would be a simple matter to use the CImage
class to load any kind of graphic (JPG, PNG, etc.) and convert it to the ImageList
format at run time. One of the nice things about a virtual list control is that only the data that is showing on the screen is actually in the control. The rest is neatly stored elsewhere in data collections or on the disc. Thus, the control does not slow down regardless of how many items are displayed.
The specific items of interest in the code are listed below. Note: I am not actually using the imagelist
s for anything besides a holding place for the eventual bitmaps.
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");
I am setting the number of items in the list control to the count in my corresponding data array. The list thinks it has this number of items even though I never actually loaded anything to it.
m_cList.SetItemCountEx((int)m_MyDataArray.GetCount(),
LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL);
This is the workhorse routine. It gets called by the list control for every line that it wants to display on the screen. Notice that there are two masks I am handling, 1 for the text and the other for the bitmap.
void CBMPListDlg::GetDispInfo(NMHDR *pNMHDR, LRESULT *pResult)
{
NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
LV_ITEM* pItem= &(pDispInfo)->item;
int nItem = pItem->iItem;
CMyDataInfo *pInfo = NULL;
if(nItem > m_MyDataArray.GetSize()-1)
return;
pInfo = (CMyDataInfo *)m_MyDataArray.GetAt(nItem);
if(pInfo == NULL)
return;
if (pItem->mask & LVIF_TEXT) {
CString csText;
if(pItem->iSubItem == 0)
csText = pInfo->m_csColumn1;
else if (pItem->iSubItem == 1)
csText = pInfo->m_csColumn2;
else if (pItem->iSubItem == 2)
csText = pInfo->m_csColumn3;
else if (pItem->iSubItem == 3)
csText = pInfo->m_csColumn4;
lstrcpyn(pItem->pszText, csText, pItem->cchTextMax);
}
if( pItem->mask & LVIF_IMAGE) {
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);
}
else {
CBitmap *cBmp = new CBitmap();
cBmp->LoadBitmap(IDB_BLANK);
m_imageList.Replace(0,cBmp,NULL);
delete cBmp;
}
pItem->iImage = 0;
}
*pResult = 0;
}
History
- Version 1.0 - April 5, 2009