CListBox is being used to display the Fonts installed in the
local machine in this project with 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 colors as in many other Owner draw list box
articles.
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 Font 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 you had better call it in the parent
dialog class constructor.
The Init() method
of the control should be called immediately after it?s
creation.
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 the system
fonts is implemented. The init method does the main font
initialization routine. The AddItem method is obsolete and
is forbidden for this class.
A class wrapper for the LOGFONT structure is defined for these
controls. The LOGFONTX class has an extra variable to store
the font type, a copy-constructor and a = operator. The init
function of the CFontDrawC class fills the internal list of
fonts of the class and then fills the control with the fonts.
Notice that it checks if the internal list is filled and if it
is doesn?t fill it again. This is done so because getting
the system fonts is a relatively time consuming job and it is
best to be done as seldom as possible.
The
internal list is filled with the Win API function
EnumFontFamilies which calls a custom function that actually
inserts the fonts in the list, which is passed as a parameter
between the functions.
The
control is filled with the names of the fonts as strings, so
FindString and SelectString can be used with these controls.
Again SetItemData is used to add a pointer to a LOGFONTX class
instance for each font.
After that in the drawing function font is received as a
pointer to the LOGFONTX structure and is drawn with that code
LOGFONTX*
pLF = ( LOGFONTX* )lpdis->itemData;
....
CFont font;
font.CreateFontIndirect( pLF );
pDC->SelectObject( &font );
pDC->DrawText( strFontName, rcText, DT_VCENTER |
DT_SINGLELINE );
When the selection in the list box is changed an event is
raised. We catch this event to update the sample text like
this
CFont
font;
font.CreateFontIndirect((LOGFONT*)m_fontList.GetItemData (m_fontList.GetCurSel()));
m_sampleText.SetFont(&font);
You
can see that to get just the pointer to the LOGFONT structure
you should write:
(LOGFONT*)m_fontList.GetItemData(m_fontList.GetCurSel());
Read here to know the general
MFC General Owner draw issues & how to solve them.
Download the source
files and Project
Files here.