CListBox example using Icons

CListBox class can contain string data type as well as Icons. In fact in Windows all controls are considered to be a window with their own Message Maps, Screen formatting functions etc., Most of these controls are derived from the parent CWnd classes and hence inherit all the abilities as stated above. This article ” CListBox example using Icons ” explains how to use a CListBox class for displaying Icons as well as text.

Creating the Derived Class – CListBox example using Icons:

An MFC application has to be created first. Before doing anything on the application, we need to derive a Custom List Box class with Fixed Owner Draw property enabled. That means, the derived CListBox class should be able to handle the DrawItem by itself. It should also set the measurements properly using MeasureItem function.

To derive a new class based on an MFC class do the following.

  1. Open the Class Wizard of the project where the new class has to be derived for CListBox example.
  2. Click on the Add Class command button.
  3. Give the name of the new class and select the base class as CListBox
  4. Use the sample below to fill out the functions needed.
  5. The derived class must be added with the functions DrawItem and MeasureItem using, the Class Wizard. This will enable the new CListBox derived class to have its own behavior of drawing items.

This sample assumes that two icons are created in the project with ids IDI_ICON1, IDI_ICON2.


CImageList g_Image_List;
/////////////////////////////////////////////////////////////////
// MyListBox constructor for CListBox example

MyListBox::MyListBox()
{
BOOL bRet = FALSE;
HICON hIcon = NULL;

// Create image list. This can be used for CListBox example
bRet = g_Image_List.Create(16, 16, ILC_COLOR32 | ILC_MASK, 5, 1);
ASSERT(bRet == TRUE);

// Add some icons
hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);
g_Image_List.Add(hIcon);

// Add some icons
hIcon = AfxGetApp()->LoadIcon(IDI_ICON2);
g_Image_List.Add(hIcon);
}
//Destructor of the derived class for CListBox example
MyListBox::~MyListBox()
{
}

void MyListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{

// TODO: Add your code to draw the specified item
//CRect members to store the position of the items
CRect rItem;
CRect rText;
CRect rIcon;
CDC* dc = CDC::FromHandle(lpDrawItemStruct->hDC);

if ((int)lpDrawItemStruct->itemID < 0)
{
// If there are no elements in the List Box
// based on whether the list box has Focus or not
// draw the Focus Rect or Erase it,
if ((lpDrawItemStruct->itemAction & ODA_FOCUS) && (lpDrawItemStruct->itemState & ODS_FOCUS))
{
dc->DrawFocusRect(&lpDrawItemStruct->rcItem);
}
else if ((lpDrawItemStruct->itemAction & ODA_FOCUS) && !(lpDrawItemStruct->itemState & ODS_FOCUS))
{
dc->DrawFocusRect(&lpDrawItemStruct->rcItem);
}
return;
}

// String to store the text, which will be added to the CListBox
CString strText;

// Get the item text.
GetText(lpDrawItemStruct->itemID, strText);

//Initialize the Item's row
rItem = lpDrawItemStruct->rcItem;

//The icon that the sample has created has a width of 16 pixels
rIcon = lpDrawItemStruct->rcItem;
rIcon.bottom = rIcon.top + 16;
rIcon.right = rIcon.left + 16;

//Start drawing the text 2 pixels after the icon
rText.left = rIcon.right + 2;
rText.top = rIcon.top;

UINT nFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER;
if (GetStyle() & LBS_USETABSTOPS)
nFormat |= DT_EXPANDTABS;

// If item selected, draw the highlight rectangle.
// Or if item deselected, draw the rectangle using the window color.
if ((lpDrawItemStruct->itemState & ODS_SELECTED) && (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)))
{
CBrush br(::GetSysColor(COLOR_HIGHLIGHT));
dc->FillRect(&rItem, &br);
}
else if (!(lpDrawItemStruct->itemState & ODS_SELECTED) &&
(lpDrawItemStruct->itemAction & ODA_SELECT))
{
CBrush br(::GetSysColor(COLOR_WINDOW));
dc->FillRect(&rItem, &br);
}

// If the item has focus, draw the focus rect.
// If the item does not have focus, erase the focus rect.
if ((lpDrawItemStruct->itemAction & ODA_FOCUS) && (lpDrawItemStruct->itemState & ODS_FOCUS))
{
dc->DrawFocusRect(&rItem);
}
else if ((lpDrawItemStruct->itemAction & ODA_FOCUS) && !(lpDrawItemStruct->itemState & ODS_FOCUS))
{
dc->DrawFocusRect(&rItem);
}

// To draw the Text set the background mode to Transparent.
int iBkMode = dc->SetBkMode(TRANSPARENT);

COLORREF crText;

if (lpDrawItemStruct->itemState & ODS_SELECTED)
crText = dc->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
else if (lpDrawItemStruct->itemState & ODS_DISABLED)
crText = dc->SetTextColor(::GetSysColor(COLOR_GRAYTEXT));
else
crText = dc->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));

CPoint pt(rIcon.left,rIcon.top);
g_Image_List.Draw(dc,0,pt,ILD_NORMAL);

dc->TextOut(rText.left,rText.top,strText);

dc->SetTextColor(crText);

}

void MyListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
// TODO: Add your code to determine the size of specified item
//The sample icons are created with height of 16 pixels
lpMeasureItemStruct->itemHeight = 16;
}

The rest of the functions of the CListBox derived class need not be changed. DrawItem function takes care of drawing the Text and the Icon. It also handles the changes of color in case of Text selected and deselected. If the new derived class is used for the List box resource, it can handle the Icons.

Creating the MFC Application – CListBox example using Icons:

Follow the steps to use the MyListBox derived from CListBox with customizations.

  1. Create a MFC Dialog based application with a List Box Resource.
  2. In the Properties dialog of the List Box in the Styles tab, check Has Strings Check box.
  3. In the Owner Draw Combo, select Fixed. Keep all the other options unchanged.
  4. Add two Icons to the application with IDs IDI_ICON1 and IDI_ICON2.
  5. Ensure that the above functions of MyListBox::MyListBox constructor, MyListBox::DrawItem and MyListBox::MeasureItem are copied into the new derived class.
  6. In the InitDialog function of the dialog class, use the following code or replace with your own values.
m_MyListBox.AddString("CListBox Example with Icon 1");
m_MyListBox.AddString("CListBox Example with Icon 2");

7.   Compile and Run the application.

Any control which needs some kind of custom features like this will need to be inherited and some functions have to be overridden.

The above sample should create a dialog box with a list box containing icons and the text typed in. Refer the mfc tutorial sample for source code.

Summary – CListBox example using Icons:

To add Icons to a list box,

  • A new list box class should be derived from CListBox
  • DrawItem and MeasureItem functions have to be overridden.
  • A CImageList class can be used to hold the list of Icons.
  • The derived class should be used for manipulating the List Box resource.