Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using a Virtual CListCtrl to Display Text and Bitmaps

0.00/5 (No votes)
9 Apr 2009 1  
Includes code to create a virtual list control that also displays bitmaps from files at run time.
BMPList.gif

Introduction

This article shows an example of using a list control to do the following:

  1. Access data object virtually
  2. Access bitmaps larger than the typical icon used in views
  3. 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 imagelists 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.

// 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);

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);

	//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;
}

History

  • Version 1.0 - April 5, 2009

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here