Snippets/ShellFont
Using the system shell font for UI elements
Using standard system fonts is important for ensuring UI consistency in your applications on Windows. When your program looks out of place, it looks like you did something wrong. Most of the time when people need to paint some UI text or need to set the default font for a control, they simply use the handle returned from GetStockObject(DEFAULT_GUI_FONT). Unfortunately, this points to MS Sans Serif size 8. Starting on Windows 2000, a separate style was created for dialog boxes (DS_SHELLFONT) that ensured the use of a common, anti-aliased font specifically designed for the shell UI. Pretty much all Windows dialog boxes and UI elements use this font. Using DEFAULT_GUI_FONT just makes things look old and hard-edged.
The system provides a font alias -- "MS Shell Dlg 2" -- that points to whatever the shell font is on your system (Tahoma for XP, Segoe UI for Vista). However, there are no standardized metrics for the size and weight of the font, so having the name doesn't help a lot. Fortunately, the metrics correspond to those of DEFAULT_GUI_FONT -- so the solution, naturally, is to get the handle for that, get the metrics, and create a font object with the same metrics but with the name replaced with "MS Shell Dlg 2."
struct AutoFont
{
AutoFont(HFONT font = NULL) : hFont(font) { }
~AutoFont()
{
if (hFont != NULL)
::DeleteObject(static_cast<HGDIOBJ>(hFont));
}
HFONT hFont;
};
HFONT UtilGetShellFont()
{
static AutoFont s_shellfont;
if (s_shellfont.hFont == NULL)
{
HFONT hGuiFont = static_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT));
LOGFONT lfGuiFont = { 0 };
if (::GetObject(hGuiFont, sizeof(LOGFONT), &lfGuiFont) == sizeof(LOGFONT))
{
_tcsncpy(lfGuiFont.lfFaceName, _T("MS Shell Dlg 2"), sizeof(lfGuiFont.lfFaceName) / sizeof(TCHAR));
lfGuiFont.lfFaceName[(sizeof(lfGuiFont.lfFaceName) / sizeof(TCHAR)) - 1] = '\0';
s_shellfont.hFont = ::CreateFontIndirect(&lfGuiFont);
}
}
return s_shellfont.hFont;
}
The AutoFont type simply ensures that the font gets properly destroyed. Just call UtilGetShellFont() and use the handle wherever you need to paint UI text.
Copyright © 2007 Roger Clark.
