Which Font is the default for MFC Dialog Controls?
Asked Answered
D

2

50

The picture below (enlarged, so you better see the differences) shows Font differences between dynamically created Edit controls (the upper two examples) and Edit Controls created from the Dialog Editor (the lower example). How can I make the font of my dynamically created CEdit controls looking like the default (the lower example)?

enter image description here

I have created the CEdit Controls like following:

obj->CreateEx(WS_EX_CLIENTEDGE, _T("EDIT"), _T(""),
              WS_CHILD | WS_VISIBLE | WS_TABSTOP,
              rect.left, rect.top, rect.Width(), rect.Height(),
              GetSafeHwnd(), reinterpret_cast<HMENU>(mId));

obj->SetFont(&mFont); // mFont was created in the Dialog Constructor
                      // with mFont.CreatePointFont(80, _T("MS Shell Dlg"));

Thanks for your help!

Dibbrun answered 19/5, 2011 at 10:30 Comment(0)
B
95

The first example is using the System font (SYSTEM_FONT), as retrieved with the GetStockObject function, which is a bitmap font that has not been used since the days of Windows 3. More information is available on Raymond Chen's blog, and Michael Kaplan's blog.

The second example is using the "MS Shell Dlg" font, just like you asked it to. That actually maps to a font called "Microsoft Sans Serif" or "MS Sans Serif", the UI font back in the days of Windows 95 and 98. This is also known as DEFAULT_GUI_FONT, which indeed used to be an accurate name for it, but alas, it is accurate no longer.

Beginning with Windows 2000 (and continued in XP), Tahoma was used as the default UI font. This is what you are seeing in the third example: Tahoma 8 pt. Unfortunately, even on those operating systems, "MS Shell Dlg" does not return Tahoma--it still returns MS Sans Serif, which is why it looks wrong.

So, you could simply specify Tahoma as the GUI font, but that wouldn't really be correct, because it would break in older versions of the OS where Tahoma isn't installed or supported, or on foreign language versions of the operating system, where a different font is used out of necessity. Instead, you're supposed to specify the DS_SHELLFONT flag, which Raymond talks about here.

And all was fine and good until Windows Vista came out. And in Windows Vista, the powers that be at Microsoft decided that Tahoma was getting a little long-in-the-tooth and Windows was due for another UI font upgrade. They developed their own special font in-house called Segoe UI, supposedly designed for optimum on-screen readability. And in a special little twist, they decided that the default size should now be 9 pt, instead of 8 pt as used by every previous version of the OS, regardless of the font face. And you would probably think that either "MS Shell Dlg", "MS Shell Dlg2", or DS_SHELLFONT (or all three) would get you this new-fangled Segoe UI font, but you'd be wrong.

Uh oh. Now things get tricky... Not only does Vista use a different font than XP that is not easily accessible with a one-size-fits-all identifier, but it also uses a different size, changing the way your dialog will look on those systems, if you can get it to display at all. In many, many places, the Windows shell team appeared to simply punt the challenge--Tahoma 8 pt is used all over the place, even with the Aero theme enabled, when it's supposed to be using Segoe UI 9 pt. This kind of thing really makes the UI look unpolished, and it was the subject of lots of nitpicking back in the early days of Vista. Now, it seems most people have forgotten about it, but the UI hasn't started looking any less scattered and inconsistent.

And you're not the Windows shell team: you can't get away with this in your own app. The Top Rules for the Windows Vista User Experience even state explicitly that you should always:

  • Use Segoe UI, the new Windows Vista system font.
  • Respect the user's settings by always referencing the system font, sizes, and colors using the Windows Theme APIs. Don't use fixed values for fonts, sizes, or colors.

To be honest, I haven't really heard a good solution to this problem yet. And I suspect that by the time I ever do, no one will need to support Windows XP anymore (although most people aren't quite there yet). But here's what I do: I extract the default system font at runtime using the SystemParametersInfo function. Fortunately, the system message box font (lfMessageFont) is the correct font face and size, regardless of the current version of Windows and the user's chosen theme.

My code to initialize windows or dialogs generally looks something like this (SystemInfo::IsVistaOrLater is a helper function I've written; the implementation is the obvious):

// Get the system message box font
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);

// If we're compiling with the Vista SDK or later, the NONCLIENTMETRICS struct
// will be the wrong size for previous versions, so we need to adjust it.
#if(_MSC_VER >= 1500 && WINVER >= 0x0600)
if (!SystemInfo::IsVistaOrLater())
{
    // In versions of Windows prior to Vista, the iPaddedBorderWidth member
    // is not present, so we need to subtract its size from cbSize.
    ncm.cbSize -= sizeof(ncm.iPaddedBorderWidth);
}
#endif

SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
HFONT hDlgFont = CreateFontIndirect(&(ncm.lfMessageFont));

// Set the dialog to use the system message box font
SetFont(m_DlgFont, TRUE);
SendMessage(hWnd, WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(FALSE, 0));

Or even easier in MFC, with the handy SendMessageToDescendants method
(m_DlgFont is a CFont object defined for the class):

// Get the system message box font
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
LOGFONT lfDlgFont = ncm.lfMessageFont;
m_DlgFont.CreateFontIndirect(&lfDlgFont);

// Set the dialog and all its controls to use the system message box font
SetFont(m_DlgFont, TRUE);
SendMessageToDescendants(WM_SETFONT, (WPARAM)m_DlgFont.m_hFont, MAKELPARAM(FALSE, 0), TRUE);

If you're not using MFC, I highly recommend implementing your own recursive version of SendMessageToDescendants. It makes the initialization code a lot simpler.

Barbur answered 19/5, 2011 at 11:15 Comment(11)
@Cody The good solution is to use a better framework. Apps built with VCL have no such troubles.Brumley
@Cody: Many thanks for the detailed explanation, I learned quite a bit. Interesting that those things go back to Windows 3. I've tried your solution but SystemParametersInfo returns MS Sans Serif instead of Tahoma, thus I initialize the font with MS Shell Dlg 2, which is mapped to the Tahoma font (target system not older than windows 2000). One note to SystemParametersInfo: I had to subtract sizeof(ncm.iPaddedBorderWidth) from ncm.cbSize to make it work on my system.Dibbrun
@Christian: Yeah, can you tell I've spent way too much time on this? Props to you for caring about how your controls look and getting them to fit in with the platform's default styling. Too few developers pay attention to this. Things go back much further than Windows 3; large portions of the Win32 API are unchanged (at least in spirit) since Windows 1.0. Backwards compatibility is a very demanding mistress. The only way that the code I've shown (using SystemParametersInfo and NONCLIENTMETRICS.lfMessageFont) would return MS Sans Serif is if that's set as your Windows font in the...Barbur
Display control panel--check under the Appearance tab. I've never seen this fail, so I'm hesitant to believe your report. And yeah, you can use "MS Shell Dlg 2" (which always maps to Tahoma), and you'll be fine on W2K and WXP, but things will look bad on Vista and 7. The rest of the world has upgraded now, so your software really does have to support Aero. And yeah, if you're compiling with version 6.0 or greater of the Windows SDK (the one that includes support for Vista and later), there was an extra member added to the struct, so the size is wrong. Updated the code with the fix.Barbur
@Cody: You can believe my report :-), and you are right, MS Sans Serif is the MessageBox Font. The reason is because I'm using Windows Classic Style (Appearance Tab in the Display Control Panel). For the target machine and for the Question, I switched to Windows XP style. My observation is, that with Windows XP style I can use your method with SystemParametersInfo and because the target machine uses this style, I will better go this way. With Windows Classic Style, the Controls from the Dialog Editor are using Tahoma but SystemParametersInfo gives me the MS Sans Serif font.Dibbrun
@Christian: That all makes sense, but your conclusion isn't quite right. And I'm a stickler for details (in case you couldn't tell). The default "Windows Classic" theme (called "Windows Standard") does in fact use the Tahoma font as the message box font. The other pre-defined color schemes, however, do not, as they have not been updated since they were first released in Windows 95/98. Regardless, though, if MS Sans Serif is the message box font in the Appearance theme, it's what all of the native controls are going to be displayed in. If you want to match them, you must use it, too.Barbur
... and that is way the Controls (from the Dialog Editor compared to the dynamically created ones) are looking different.Dibbrun
Great answer! FWIW, I usually weasel around the problem by "stealing" the font from some default-created dialog or control.Momism
@DavidHeffernan How can I do that on VCL? Do you have any good 'designing forms on VCL' resource to share? Thanks!Bracer
@dccarmo #8297284Brumley
The default dialog templates created by VS specify the dialog window style DS_SHELLFONT. This flag supersedes WS_SETFONT. It causes MS Shell Dlg to be replaced with MS Shell Dlg 2, so your dialog fonts all magically become Tahoma. This happens through internal functions called FixupDlgLogFont and/or FixupDlgFaceName (source: reverse engineering user32.dll). Interestingly, all the standard Windows dialogs do not use DS_SHELLFONT in their dialog templates and as such use MS Shell Dlg, which is Microsoft Sans Serif on western systems (not to be confused with MS Sans Serif!!!).Toussaint
P
0

In my projects i copy the font from the main dialog. But the main dialog must be built by the Dialog Editor.

#include <windowsx.h> // for Get/SetWindowFont()

SetWindowFont(editHwnd, GetWindowFont(mainDlgHwnd), true);
Pouliot answered 30/9, 2022 at 5:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.