如何计算静态控件中文本的实际高度

How to compute the actual height of the text in a static control

我的简单 Win32 对话框包含两个静态文本控件(IDC_STATIC_TITLE 和 IDC_STATIC_SECONDARY),这是它在资源编辑器中的样子:

在运行时,动态更新文本第一个字符串。此外,该文本字符串的字体被替换,使其大于其下方的 IDC_STATIC_SECONDARY 字符串。生成的文本字符串可能跨越一行、两行或更多行。

我希望在 运行 时将另一个包含辅助文本的静态控件直接放置在标题字符串下方。但是,我在 WM_INITDIALOG 回调中对 re-position 此控件的最终尝试效果不佳。第二个字符串与第一个重叠。我想我可以使用带有 DT_CALCRECT 的 DrawText 来计算主要文本字符串的高度,然后根据结果移动次要文本字符串。我的代码有点短,如下所示:

DrawText returns 坐标为 {top=42 bottom=74 left=19 right=461} 的 RECT 从顶部减去底部是“32”。这似乎有点短。我怀疑我没有正确调用 API and/or 逻辑单元和像素单元之间的不同映射问题。

这是相关的 ATL 代码。 CMainWindow class 只是继承自 ATL 的 CDialogImpl class.

CMainWindow::CMainWindow():
_titleFont(NULL),
_secondaryFont(NULL)
{
    LOGFONT logfont = {};
    logfont.lfHeight = 30;
    _titleFont = CreateFontIndirect(&logfont);
}

LRESULT CMainWindow::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    CString strTitle;
    RECT rectDrawText = {}, rectTitle={}, rectSecondary={};
    CWindow wndTitle = GetDlgItem(IDC_STATIC_TITLE);
    CWindow wndSecondary = GetDlgItem(IDC_STATIC_SECONDARY);

    this->GetDlgItemText(IDC_STATIC_TITLE, strTitle);

    wndTitle.SetFont(_titleFont);   // font created with Create

    wndTitle.GetWindowRect(&rectTitle);
    wndSecondary.GetWindowRect(&rectSecondary);
    ScreenToClient(&rectTitle);
    ScreenToClient(&rectSecondary);

    rectDrawText = rectTitle;
    DrawText(wndTitle.GetDC(), strTitle, strTitle.GetLength(), &rectDrawText, DT_CALCRECT|DT_WORDBREAK); // compute the actual size of the text

    UINT height = rectSecondary.bottom - rectSecondary.top;  // get the original height of the secondary text control
    rectSecondary.top = rectDrawText.bottom;                 // position it to be directly below the bottom of the title control
    rectSecondary.bottom = rectSecondary.top + height;       // add the height back
    wndSecondary.MoveWindow(&rectSecondary);

    return 0;
}

我做错了什么?

尽管它的名字听起来像什么,wndTitle.GetDC() 并不 return 某些 pointer/reference 是 CWindow 的一部分并且每次调用都是一样的。相反,它每次都为 window 检索一个全新的设备上下文。 (它基本上是 GetDC() Windows API 调用的精简包装器,一直到 returning 一个 HDC 而不是 MFC 等价物。)

尽管与 window 相关联,但此设备上下文加载了默认参数,包括默认字体(IIRC 为 that old "System" font from the 16-bit days (most of this screenshot))。

所以你需要做的是:

  1. 调用 wndTitle.GetDC() 获取 HDC
  2. 调用 SelectObject() 到 select 正确的 window 字体(你可以使用 WM_GETFONT 得到这个;不确定 MFC 是否有包装函数) , 为步骤 4
  3. 保存 return 值,前一个字体
  4. 致电DrawText()
  5. SelectObject()打电话给select the previous font back in
  6. 致电 wndTitle.ReleaseDC() 声明您已完成使用 HDC

更多详情请见the MSDN page for CWindow::GetDC()