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.