Demo app. ChooseFont() button opens the font common dialog for comparison.
Introduction
To choose a font is an easy thing. Calling ChooseFont()
, or from MFC
creating a CFontDialog
object, will do the trick. This will open a new dialog
window from which the user can select a font to be used. Now, it's not always desired to
open new dialogs everywhere you go along to do things. The more windows opened, the harder to use.
A lot of applications have a lot of different properties to be set, and it would be nice
if all those are accessible from one dialog. E.g. cell formatting in MS Excel opens a
tabbed dialog where you can set different properties. One of the tabs is the Font tab.
This article describes how to achieve this.
Background
After searching the net for a solution to having a font properties dialog as a child
window, nothing came up. The obvious idea is to somehow use the ChooseFont()
function and add it as a child dialog. This however seems impossible. Please correct me
if I'm wrong.
The second most obvious idea is to write all code yourself. That is the solution in this
article. It's not all true though, some code was without regret stolen from Chris Losinger's
excellent Font Combo.
Also, Hans Dietrichs extension to the Font Combo,
XFontCombo was checked out in
order to add OpenType font type support. But since this method doesn't yield the same
result as the ChooseFont()
does, it was discarded.
Using the code
The main object is the class
class CFontPropertiesDialog : public CDialog
Add its resource template to your .rc file, add a bitmap to be displayed along TrueType fonts,
create an instance of this class and you're done.
Step by step
Follow these step-by-step instructions to make it work.
1. Insert the bitmap, font_tru.bmp, as a new bitmap resource. Name the resource IDB_TTF_BMP.
2. Copy the dialog resource to your .rc file.
3. Make sure you have the definitions in your resource.h file. The following items should be included:
#define IDD_FONTPROPERTIES_DIALOG 130
#define IDC_STRIKEOUT_CHECK 1001
#define IDC_UNDERLINE_CHECK 1002
#define IDC_PREVIEW 1003
#define IDC_FONTFACE_COMBO 1004
#define IDC_FONTSTYLE_COMBO 1005
#define IDC_FONTSIZE_COMBO 1006
#define IDC_SCRIPT_COMBO 1007
#define IDC_SCRIPT_STATIC 1009
#define IDC_EFFECTS_STATIC 1010
#define IDC_SAMPLE_STATIC 1011
#define IDC_FONTFACE_STATIC 1012
#define IDC_FONTSTYLE_STATIC 1013
#define IDC_FONTSIZE_STATIC 1014
(The actual number for
IDD_FONTPROPERTIES_DIALOG
may have to be altered to a unique value.)
4. Add a member of the CFontPropertiesDialog
class, m_dlgFonf
, to your main dialog,
CMyDialog
.
5. Initialize the dialog font data if necessary, then create and position the child dialog.
BOOL CMyDialog::OnInitDialog()
{
CDialog::OnInitDialog();
LOGFONT lf;
GetFont()->GetLogFont(&lf);
m_dlgFont.SetLogFont(&lf);
if (!m_dlgFont.Create(-1, this))
return FALSE;
CRect rc;
GetClientRect(&rc);
m_dlgFont[0].SetWindowPos(NULL, rc.left, rc.top, rc.Width(),
rc.Height(), SWP_NOZORDER);
return TRUE;
}
Public Interface
BOOL Create(DWORD dwEnumFlags = -1, CWnd* pParentWnd = NULL);
Creates the child dialog. The
dwEnumFlags
parameter describes what font types are
to be enumerated, and also what visual elements should be displayed. Any combination of the
following values can be used (with bitwise or):
RASTER_FONTTYPE
DEVICE_FONTTYPE
TRUETYPE_FONTTYPE
FPD_DISPLAY_SCRIPT
FPD_DISPLAY_EFFECTS
FPD_DISPLAY_ALL
void SetLogFont(const LOGFONT *lpLogFont);
You can initialize the dialog with a font. This method can alse be called after the dialog has
been created to change the font displayed.
const LOGFONT& GetLogFont();
Get the currently selected font from the dialog.
void SetTextColor(COLORREF clr);
Sets the text color in the preview control. Default is black.
COLORREF GetTextColor() const;
Gets the text color currently used by the preview control.
void SetBkGndColor(COLORREF clr) { m_clrPreviewBkGnd = clr; }
Sets the background color of the preview control. Default is
::GetSysColor(COLOR_BTNFACE)
.
Overridables
virtual void LayOutControls();
This function is responsible for changing UI elements depending on the different display flags.
Implementation details
To get all font names from the system the
EnumFontFamilyEx
function is used. Then, when
the user selects a font face, this function is called again to get available styles and point sizes.
There is really not much to talk about here, since this function is well described in the documentation.
The combo box displaying font names is an owner drawn control. The code is a slightly modified version
of Chris Losingers Font Combo.
If you customize the dialog template, you might have to go through the
LayOutControls()
function to make sure it reposition the controls as expected. Also it might
be a good idea to not delete elements from the template, but rather hide and disable them if they are
not wanted in the GUI.
Tradeoffs
Initially, the support for displaying which fonts are OpenType, Hans Dietrichs
XFontCombo
was checked out. But since this code doesn't yield the same result as the
ChooseFont()
does, this was abandonned, and the dialog now displays OpenTypes as plain TrueTypes. Not many application
need to make that distinction anyway. However, if you do want to have this support, you can easily
add it. At the top of the
FontPropertiesDialog.cpp
file, you can change:
#define IDENTIFY_OPENTYPE 0
to 1. If you do this, make sure you have Hans Dietrichs source code files IsOpenType.h and GetFontFile.h
and their cpp file counterparts.
A color picker has been omitted by design. Different application use different color pickers. It's as easy
as that. It's a look-and-feel thing. A color picker can be added without much effort.
A thought that came to mind was to use the resource template for ChooseFont()
from the
commdlg.dll file. This way, the dialog should automatically change language depending on the system,
and also get the automatic help to work.
This strategy was also abandonned in favor of customizability. Having the dialog resource at hand will
make this a lot easier.
Points of Interest
The preview control in the common dialog seems to change its caption when selecting different character
sets (script combo box). For instance, if Western is selected, the control shows "AaBbYyZz". Selecting another
character set will change this to what seems to be a more appropriate string for that character set.
How this works, I havn't been able to figure out. The implementation in CFontPropertiesDialog
uses the window text supplied in the dialog template unmodified for every character set.
The enumeration process does not appear to be complete for the font common dialog. On my system I have
several TrueType fonts installed which supports more styles than the four most common ones:
Regular, Italic, Bold and Bold Italic. E.g. these fonts might have the styles like Oblique and Bold Oblique etc.
These styles does not appear in the font common dialog but it does in CFontPropertiesDialog
.
My guess is that the font common dialog just sets the four basic styles for TrueType fonts,
whithout using the enumeration process.
References
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.