CListBox in MFC is a powerful control. It can be used for
displaying the normal text and even custom data like pictures.
Whenever such custom behavior is needed, a new class has to be
derived from CListBox and the MeasureItem and DrawItem
functions should be over-ridden and the CListBox based control
should be created as an owner draw control.
These CListBox
functions MeasureItem and DrawItem are common to all MFC
controls. All controls use this function?s default behavior
to draw their GUI. The project in this article illustrates an
owner-draw list box. The class uses an abstract object to draw
the items. In this case a class derived from the abstract
object is created to make the control list pictures, but
making you own classes that implement you ideas for owner-draw
lists, derived from it should be easy.
The name of the abstract class is CdrawC. This abstract class
contains methods that are called from the list box class only.
They are
virtual
void DrawItem(LPDRAWITEMSTRUCT lpdis, bool bHasFocus) = 0;
Draws the item using
the Win32 DRAWITEMSTRUCT.
virtual
void MeasureItem(LPMEASUREITEMSTRUCT lpmis) = 0;
Sets the item size
once or every time depending of the owner-draw style: fixed or
variable.
virtual
void InitLBox(CListBox* pLBox) = 0;
Initializes the
control holding the class if it is a CListBox (or derived from
it).
virtual
int AddItemLst(CListBox* pLBox, UINT nItem) = 0;
Adds an item to the
control holding the class if it is a CListBox (or derived from
it).
Using the CListBox derived owner draw class:
-
This abstract class is added to the list box via it?s method SetDrawC. It must be added before the control is created, so it
should be called in the CDialog constructor.
-
The Init() method of the control should be called immediately after it?s
creation.
-
Items are added with the AddItem function of the control. This AddItem is over-ridden
to call another function which calls the AddItemLst.
-
List boxes using from this type can be created either dynamically or
using the dialog editor and after adding a variable of
type CListBox just
rename it with CODrawLBox.
Don?t forget to call SetDrawC and Init.
-
List boxes must be created with the following styles: LBS_HASSTRINGS,
LBS_NOTIFY, LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE.
In this particular example a list box, listing pictures that
are bitmaps in the project?s resources is implemented. The
init method is obsolete for there is no initialization needed
for this case. The AddItem implementation inserts an
unused string in the control and gets the bitmap resource id
and from it gets the handle to the bitmap, then it inserts the
handle in the item data field of the control. Also two class
constants are used to set the size of the pictures (PicSizeX
and PicSizeY). When you use your pictures be sure to change these constants so that
your pictures fit in the device context.
int CPicDrawC::AddItemLst(CListBox* pLBox, UINT nItem)
{
int n;
n = pLBox->AddString("un");
HBITMAP hbmp =
(HBITMAP)LoadImage(AfxGetApp()->m_hInstance,
MAKEINTRESOURCE(nItem), IMAGE_BITMAP, PicSizeX, PicSizeY,
0L);
pLBox->SetItemData(n, (DWORD)hbmp);
return n;
}
After that in the drawing function the handle to the bitmap is received
as item data and like this:
HBITMAP hbmp = (HBITMAP)lpdis->itemData;
CDC MemDC;
MemDC.CreateCompatibleDC(&dc);
MemDC.SelectObject(hbmp);
dc.BitBlt(rect.left+5, rect.top+1, PicSizeX, PicSizeY,
&MemDC, 0, 0, SRCCOPY);
When the selection in the list box is changed an event is
raised. We catch this event to update the sample picture box
like this:
CRect rect;
m_samplePic.GetClientRect(rect);
HBITMAP hbmp =
(HBITMAP)m_picList.GetItemData(m_picList.GetCurSel());
CDC MemDC, *pDC = m_samplePic.GetDC();
MemDC.CreateCompatibleDC(pDC);
MemDC.SelectObject(hbmp);
pDC->BitBlt(rect.left+10, rect.top+10,
m_picDrawc.PicSizeX, m_picDrawc.PicSizeY, &MemDC, 0, 0,
SRCCOPY);
You can see that to get just the handle to the bitmap currently selected
you need to use this code:
(HBITMAP)m_picList.GetItemData(m_picList.GetCurSel());
Download the Sample
Source here. Read here to know the
MFC General Owner draw issues & how to solve them.