It is necessary to switch off the "ClearType" property of the default font for all dialog controls. It is possible to do that for one control by setting
logfont.lfQuality = ANTIALIASED_QUALITY
There are a lot of suggestion how to do the same for modal dialogs (http://neelaakash.wordpress.com/2007/12/31/change-default-dialog-font-of-cdialog/ and others), but that should be done for non-modal dialogs (are instantiated with new and Create(…) methods). I've tried to do that myself:
Override 'Create' method, and modify dialog template:
BOOL CActivationChildDialogLicenseInfo::Create(UINT nIDTemplate,
CWnd* pParentWnd)
{
CDialogTemplate dlt;
int nResult;
// load dialog template
if (!dlt.Load(MAKEINTRESOURCE(nIDTemplate))) return -1;
// set your own font, for example “Arial”, 10 pts.
dlt.SetFont(L"Arial", 12);
// get pointer to the modified dialog template
LPSTR pdata = (LPSTR)GlobalLock(dlt.m_hTemplate);
// let MFC know that you are using your own template
m_lpszTemplateName = NULL;
InitModalIndirect(pdata);
// display dialog box
nResult = CActivationChildDialog::Create(nIDTemplate, pParentWnd);
// unlock memory object
GlobalUnlock(dlt.m_hTemplate);
return nResult ;
}
Seems like this method do nothing (it is called, I've checked that with putting break-point inside).
I've tried to call
nResult = CActivationChildDialog::Create(NULL, pParentWnd);
…but got a lot of ASSERTs.
I've also tried to override the 'OnSetFont' method:
void CActivationChildDialogLicenseInfo::OnSetFont(CFont *pFont)
{
CActivationChildDialog::OnSetFont(pFont);
LOGFONT logfont;
pFont->GetLogFont(&logfont);
LOGFONT logfont2=logfont;
pFont->DeleteObject();
logfont2.lfItalic = true;
logfont2.lfQuality = ANTIALIASED_QUALITY;
pFont->CreateFontIndirect(&logfont2);
}
That causes ASSERT during run-time and resulted in a VERY big font being used (lost default font settings, doesn't accept new specified settings)… I don't know why.
Please advise, how can I change a default dialog font that will be "inherited" by all dialog controls?
Thank you very much.
Best Answer
First off: the simple, reliable way to do this is to create the dialog and then send
WM_SETFONT
(or callSetFont()
) to the dialog and each control in it. I'll show you how to do that below, but first, here's why the two strategies you've already tried didn't (and can't) work:Modifying the dialog template
First off, you should be calling
CDialog::CreateIndirect()
if you wish to use a dialog template that you've already loaded.But don't bother. The dialog template contains only the face name and point size - it does not allow you to specify other LOGFONT values such as
lfQuality
. If it did, you could simply specify that in your resource definition and avoid writing any runtime code at all!Intercepting
WM_SETFONT
In theory, you could make this work. But it's not practical. Your code has several problems: first off, you'd have to intercept this message for every child control in order for it to do anything useful: the dialog itself probably doesn't render any text. But worse, you're passing the original font to the base class (which hands it to the default window procedure, which stores it internally for later use) and then immediately destroying it - this means the dialog (and everything else using that font, including all of the child controls) will be trying to draw text using a bogus font, and reverting to the default font as a result. Finally, you're creating a new font attached to a temporary object (
pFont
) created and destroyed by MFC - internally, the CFont object you're working with will be detached from the font handle and destroyed, leaking a handle to a font object that nothing uses.Leaky abstractions: a note on HFONT and CFont
HFONT is a handle type that Windows uses to represent a font object. Like most of GDI, there are specific functions for creating fonts, and the general-purpose
DeleteObject()
function for destroying them.CFont is a light-weight wrapper class for HFONTs. A CFont instance can be attached and detached from an existing HFONT, or used to create a new one. If a CFont instance is still attached to a HFONT when its deconstructor executes, it will call
DeleteObject()
to destroy the underlying object. Internally, MFC utilizes temporary CFont instances that are attached and detached from HFONTs when calling various message handlers (such as OnSetFont). It's worth remembering that internally, Windows knows nothing about CFont, and a single HFONT may belong to 0 or more CFont instances at any given point in time.A note on fonts and WM_SETFONT
When you create a new font - whether or not it is wrapped in a CFont object - you are the owner of that font, and it is your responsibility to destroy it once you are finished using it. Passing it to
WM_SETFONT
(CWnd::SetFont()
) doesn't change ownership! This is actually quite useful, as it allows you to pass the same font to multiple windows without worrying about which one will destroy it - you're still the owner, and so you can (and must) destroy it yourself (once there are no windows still using it).Finally - how to quickly create and set a font on a dialog and all its children
So you should now have enough background to understand the necessary steps:
Example