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

时间:2010-07-19 16:26:22

标签: c++ winapi mfc

必须为所有对话框控件关闭默认字体的“ClearType”属性。通过设置

可以为一个控件执行此操作
logfont.lfQuality = ANTIALIASED_QUALITY

对于模态对话框(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 ;
}

似乎这个方法什么都不做(它被称为,我已经检查过将断点放在里面)。 我试过打电话

nResult = CActivationChildDialog::Create(NULL, pParentWnd);

......但是得到了很多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);
}

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

请注意,如何更改所有对话框控件“继承”的默认对话框字体?

非常感谢。

1 个答案:

答案 0 :(得分:8)

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

修改对话框模板

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

但不要打扰。对话框模板仅包含面部名称和磅值 - 它允许您指定其他LOGFONT值,例如lfQuality。如果做了,您只需在资源定义中指定它,并避免编写任何运行时代码!

拦截WM_SETFONT

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

Leaky抽象:关于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对象中 - 您是该字体的所有者,并且您有责任在完成使用后销毁它。 Passing it to WM_SETFONT (CWnd::SetFont()) doesn't change ownership!这实际上非常有用,因为它允许你将相同的字体传递给多个窗口而不用担心哪个会破坏它 - 你仍然是所有者,所以你可以(并且必须)自己销毁它(一旦没有窗户仍在使用它)。

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

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

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

    // 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;
    }