如何更改非模态对话框的默认CDialog字体?

Bud*_*dda 4 c++ winapi mfc

对于所有对话框控件,必须关闭默认字体的"ClearType"属性.通过设置可以对一个控件执行此操作

logfont.lfQuality = ANTIALIASED_QUALITY
Run Code Online (Sandbox Code Playgroud)

有很多建议如何对模态对话框做同样的事情(http://neelaakash.wordpress.com/2007/12/31/change-default-dialog-font-of-cdialog/等),但那应该是可以用于非模态对话框(使用new和Create(...)方法实例化).我试过自己这样做:

覆盖"创建"方法,并修改对话框模板:

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 ;
}
Run Code Online (Sandbox Code Playgroud)

似乎这个方法什么都不做(它被称为,我已经检查了内部的断点).我试着打电话

nResult = CActivationChildDialog::Create(NULL, pParentWnd);
Run Code Online (Sandbox Code Playgroud)

......但是得到了很多ASSERT.

我也尝试覆盖'OnSetFont'方法:

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);
}
Run Code Online (Sandbox Code Playgroud)

这会在运行时导致ASSERT并导致使用非常大的字体(丢失默认字体设置,不接受新的指定设置)...我不知道为什么.

请指教,如何更改所有对话框控件将"继承"的默认对话框字体?

非常感谢你.

Sho*_*og9 8

首先:简单,可靠的方法是创建对话框,然后发送WM_SETFONT(或调用SetFont())对话框及其中的每个控件.我将在下面告诉你如何做到这一点,但首先,这就是为什么你已经尝试过的两种策略没有(也做不到)的原因:

修改对话框模板

首先,CDialog::CreateIndirect()如果您希望使用已加载的对话框模板,则应该进行调用.

但是不要打扰.该对话框的模板包含只有面部名称和大小-它并没有让你指定其他LOGFONT值,如lfQuality.如果是这样,您可以在资源定义中指定它,并避免编写任何运行时代码!

拦截 WM_SETFONT

从理论上讲,你可以做到这一点.但这不切实际.您的代码有几个问题:首先,您必须为每个子控件拦截此消息,以便它执行任何有用的操作:对话框本身可能不会呈现任何文本.但更糟糕的是,您将原始字体传递给基类(将其传递给默认窗口过程,该过程在内部存储以供以后使用)然后立即销毁它 - 这意味着对话框(以及使用该字体的所有其他内容,包括所有子控件)将尝试使用伪造字体绘制文本,并因此恢复为默认字体.最后,您要创建一个附加到临时对象的新字体(pFont)由MFC创建和销毁 - 在内部,您正在使用的CFont对象将从字体句柄中分离并被销毁,泄漏句柄到没有使用的字体对象.

漏洞抽象:关于HFONT和CFont的说明

HFONT是Windows用于表示字体对象的句柄类型.像大多数GDI一样,有创建字体的特定功能,以及DeleteObject()用于销毁它们的通用功能.

CFont是HFONTs的轻量级包装机.CFont实例可以与现有的HFONT连接或分离,或用于创建新的实例.如果CFont实例在解析器执行时仍然附加到HFONT,它将调用DeleteObject()以销毁底层对象.在内部,MFC利用在调用各种消息处理程序(例如OnSetFont)时附加和分离HFONT的临时CFont实例.值得记住的是,在内部,Windows对CFont一无所知,并且在任何给定的时间点,单个HFONT可能属于0个或更多CFont实例.

关于字体和WM_SETFONT的注释

当您创建一个新字体 - 无论它是否包含在CFont对象中 - 您是该字体的所有者,并且您有责任在完成使用后销毁它.将它传递给WM_SETFONT(CWnd::SetFont())并不会改变所有权!这实际上非常有用,因为它允许你将相同的字体传递给多个窗口而不用担心哪个会破坏它 - 你仍然是所有者,所以你可以(并且必须)自己销毁它(一旦没有窗户仍在使用它).

最后 - 如何在对话框及其所有子对象上快速创建和设置字体

所以你现在应该有足够的背景来理解必要的步骤:

  1. 创建对话框
  2. 创建所需的字体
  3. 将字体传递给对话框及其子对象(通过发送WM_SETFONT消息,或通过调用CWnd :: SetFont ...本身发送WM_SETFONT消息).
  4. 当对话框被销毁时,也会破坏您的字体.

// define this as a class member - class destructor then handles step four!
CFont m_nonCleartypeFont; 

BOOL CActivationChildDialogLicenseInfo::Create(UINT nIDTemplate, 
                                               CWnd* pParentWnd)
{
  // step one: create dialog normally
  BOOL nResult = CActivationChildDialog::Create(nIDTemplate, pParentWnd);

  // step two: create custom font
  // relying on destructor to destroy font once we're done with it
  // so be careful to only create it once!
  if ( NULL == m_nonCleartypeFont.m_hObject )
  {
    CFont* pOriginalFont = GetFont(); // use template font as... template!

    // pull information from original font  
    LOGFONT logfont;
    pOriginalFont->GetLogFont(&logfont);

    // make font adjustments: 
    // specify italics
    logfont.lfItalic = true;
    // and non-cleartype antialiasing
    logfont.lfQuality = ANTIALIASED_QUALITY;

    // create our font based on adjusted information
    m_nonCleartypeFont.CreateFontIndirect(&logfont);
  } 

  // step three: set our custom font on the dialog and all children
  SetFont(&m_nonCleartypeFont, FALSE);
  // Send message to quickly set this font for all children. 
  // See documentation for SendMessageToDescendants()
  // - this is actually the example given!
  SendMessageToDescendants(WM_SETFONT,
      (WPARAM)m_nonCleartypeFont.m_hObject,
      MAKELONG(FALSE, 0), 
      FALSE);

  return nResult;
}
Run Code Online (Sandbox Code Playgroud)