Visual C++ Example:
Cool MFC Font Combo Box
with source codes
(CComboBox)
|
By Chris Losinger, Dave Schumann.
Introduction
This control
gives you a font selection combo
with font preview and optional sample text. It also
features self-adjusting drop-width, to handle any size font
name and sample text.
Updates
Dave
Schumann has updated Chris' font selector dialog control.
It was almost exactly what he needed. It lacked, however,
an easy way to sync it up with data, so he added a simple
DDX function for data exchange. Performance was also
improved by creating the fonts once and caching them in a
map (Chris' version creates a font every time a list box
item needs to be drawn).
Usage
Original
version:
-
Add the
following files to your workspace:
-
FontPreviewCombo.cpp
-
FontPreviewCombo.h
-
res/Font_tru.bmp
- make sure this resource is called IDB_TTF_BMP .
This is the TrueType Font
glyph.
-
Add a combobox
to your dialog.
-
Make
sure the following styles are selected:
-
Type:
Drop List
-
Owner
draw: Variable
-
Has
Strings (yes)
-
Sorting
is OK. It will sort on font name.
-
Add a
member of type CFontPreviewCombo to your
dialog and attach it to your control.
-
Set the
combo style, font size, sample text, etc..
-
In your
dialog's OnInitDialog , call the Init
function of the CFontPreviewCombo . This
will load the fonts into the control.
Dave
Schumann's updated version
-
Set the combo
style, font size, sample
text, etc.
Now that fonts are
pre-made, font size and combo style are no longer
public members; instead, they have Get and Set
accessors. The Set accessors, by default,
re-initialize the control, since changing these
variables requires re-making the fonts. IF
you're going to initialize the control yourself, you
can disable this automatic behavior (so as to avoid
unnecessary reinitialization). For example:
m_fontCombo.SubclassDlgItem (IDC_FONTCOMBO, this);
m_fontCombo.m_csSample = "No Fate But What We Make";
m_fontCombo.SetFontHeight (19, false);
m_fontCombo.SetPreviewStyle (CFontPreviewCombo::SAMPLE_ONLY, false);
m_fontCombo.Init();
The
second argument to SetFontHeight() and SetPreviewStyle()
is an optional bool that defaults to true and
specifies whether to reinitialize the dialog. There's
only a benefit to setting it to false if you're going
to set both font height AND preview style, in which
case you should do both and then call Init() .
(Note that if you only set one, you can simply omit
the second argument as well as your own call to Init() .
If you call neither accessor you need to call Init()
yourself.)
-
If it
wasn't done above, then in your dialog's OnInitDialog() ,
call the Init() function of the CFontPreviewCombo .
This will load the fonts into the control. You should
call the base class method (CDialog::OnInitDialog() )
after initializing the font combo box control.
-
In this
version of the control, you can add code to your
override of the DoDataExchange() member
function to handle getting and setting the font
facename. If you create a member m_fontFaceName ,
then you can add a call like this in DoDataExchange()
after the AFX calls:
DDX_FontPreviewCombo (pDX, IDC_FONTCOMBO, m_fontFaceName);
When the
dialog is displayed, this will select the font that
corresponds to the value of m_fontFaceName ,
if such a font exists. When the dialog is closed, m_fontFaceName
will contain the selected font's name.
How it
works
This is a
very basic owner-drawn CComboBox .
In MFC, an
"owner-drawn" combo box means it handles two
functions: MeasureItem and DrawItem .
MeasureItem
MeasureItem
is called once per item, and it's where you provide
the height of each list item. This way, Windows knows how
large to make the drop list and where to draw your item
within the drop list. In this case, we're allowing each
item to be a different height (that's the Owner Draw :
Variable part, above). We're also measuring the width of
each item, so we can tell how wide we need to make the
drop list (we'll get to that in OnDropDown )
DrawItem
This is a
bit more complicated than MeasureItem , but
not much. DrawItem is called each time
Windows needs to draw an individual item in the control. A
set of flags are passed in that describe the item itself
and what kind of drawing we should do (focused, disabled,
edit only, drop list, etc.). All you need to do is draw
the item in the rectangle provided, in the right style.
So, we draw the TTF glyph if we need to, then we draw the
font name and sample text in the style that the user has
ucancode.neted for (font + sample, no sample, etc). Again, this
happens once for each item - you only draw one item at a
time.
Other info
The rest of
the code in the class handles getting the list of fonts,
and setting the drop list width:
EnumFonts
This
function tells Windows to give you the list of available
fonts. You provide a callback function with a specific
signature and Windows will call that function once per
font. We use the callback as a place to do an AddString
into the combo, to add the font name and type for each
font. FYI, each of these AddString calls will result in
one call to MeasureItem.
OnDropDown
This is the
last little bit of interesting code. This gets called when
you hit the little drop-down arrow. In this function, we
determine how wide we need our drop list to be. We want it
to be wide enough to hold the largest item, based on the
style. When we know how wide we want it to be, we call CComboBox::SetDroppedWidth(nWidth)
to tell Windows that out list should be nWidth units wide.
FYI, it will always be at least as wide as the edit
control, but sometimes we need to make it wider.
Downloads
Download
demo project - 41Kb
Download source - 4Kb
|