9

Microsoft 在其 UI 指南中使用对话长度单位 (DLU)。如何将它们转换为像素?

据我所知,DLU 取决于系统字体大小。你能建议一些在 Delphi for Win32 中进行这种转换的简单方法吗?

4

4 回答 4

18

首先我们从什么是对话单元开始。

为此,我将引用我自己未回答的问题之一:

什么是对话单元?

对话框是基于用户首选字体大小的度量单位。定义一个对话单元,使平均字符为 4 个对话单元宽乘以 8 个对话单元高:

在此处输入图像描述

这意味着对话单元:

  • 用所选字体更改
  • 使用选定的 DPI 设置更改
  • 不是方形的

我还将引用我自己的另一个未回答的问题

您可以查看Windows UX 指南以了解这些测量值的来源。简短的版本是:

  • dlu =对话单元
  • dlu 基于字体大小(项目随用户的字体大小而变化
  • 水平dlu 与垂直 dlu 不同 dlu不是方形的

这来自对话单元的定义:平均字符为 8dlus high x 4dlus wide

乔治亚 14 分:

在此处输入图像描述

如果您使用较小的字体(即 8pt Tahoma verses 14pt Georgia),则 dlus 会变小:

Segoe UI 9pt:

在此处输入图像描述

注意:您会注意到分辨率(即 dpi)对讨论没有影响。

所以你需要的是一个字符的平均大小。微软有一种计算平均字符大小的官方技术。

  • 平均身高:

    GetTextMetrics(dc, {var}textMetrics);
    averageHeight := textMetrics.tmHeight;
    
  • 平均宽度:

    使用测量字符串ABCDEFGHIJLKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzGetTextExtentPoint32,然后除以 52:

    GetTextExtentPoint32(dc,
          PChar('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 52, Size));
    averageWidth := size.cx / 52.0;
    

所以现在你需要一个水平和一个垂直对话单元的大小。请记住,水平对话单元是平均字符宽度的 1/4,垂直 dlu 是平均字符高度的 1/8:

procedure GetDlus(dc: HDC; out HorizontalDluSize, VerticalDluSize: Real);
var
   tm: TTextMetric; 
   size: TSize;
begin
   GetTextMetric(dc, tm);
   VerticalDluSize := tm.tmHeight / 8.0;

   GetTextExtentPoint32(dc,
         PChar('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 52,
         size);
   HorizontalDluSize := size.cx / 52.0;
end;

注意:任何代码都会发布到公共领域。无需归属。

于 2012-05-21T22:34:11.010 回答
11

您应该使用该MapDialogRect()功能。

RECT以对话单位传入 a ,并RECT返回以像素为单位的等价物。请注意,您需要对话句柄才能提供MapDialogRect()足够的上下文。该函数需要知道字体才能执行转换。


如果您想使用GetDialogBaseUnits(),请记住 Raymond Chen 所说的,GetDialogBaseUnits 是一个缸

您可以从这篇文章的标题中猜到,GetDialogBaseUnits 是个垃圾。由于 GetDialogBaseUnits 没有 HWND 参数,因此它不知道您要检索哪个对话框的 DLU。所以它猜测。

而且它总是猜错。

GetDialogBaseUnits 返回使用默认系统字体的对话框的对话框基本单位。但是没有人再使用默认的系统字体了。它尖叫着“又老又笨”。但出于兼容性原因,它仍然是默认设置。(因此 GetDialogBaseUnits 也是如此。)

如果您必须从 DLU 计算像素尺寸,并且您没有对话框的句柄,那么您必须使用此处概述的方法:如何使用非基于系统的字体计算对话框基本单位


但是,您在评论中明确表示,对于您的问题,您实际上不需要从 DLU 转换为像素。您可以使用 Delphi 内置的表单缩放来确保您的表单的大小适合流行的字体缩放。

于 2011-07-29T09:14:33.577 回答
0

这是用于转换 DLU ↔ 像素的 C 代码:

HWND hDlg = ...;                   // The handle to the dialog

LPDLGTEMPLATE *dlgTemplate = ...;  // The template for the same dialog
SIZE dlgSize;                      // Only needed for converting DLU -> pixels
if (dlgTemplate->style == 0xFFFF0001)
{
    dlgSize.cx = ((DLGTEMPLATEEX *)dlgTemplate)->cx;
    dlgSize.cy = ((DLGTEMPLATEEX *)dlgTemplate)->cy;
}
else
{
    dlgSize.cx = dlgTemplate->cx;
    dlgSize.cy = dlgTemplate->cy;
}

RECT rc = { 0, 0, 4, 8 };
MapDialogRect(hDlg, &rc);

// To convert dlgSize to pixels, use:
SIZE wndSize = { dlgSize.cx * rc.right / 4, dlgSize.cy * rc.bottom / 8 };

// To convert wndSize to DLUs, use:
SIZE dlgSize2 = { size.cx * 4 / rc.right, size.cy * 8 / rc.bottom };
assert(dlgSize1 == dlgSize2);
于 2022-01-15T06:17:04.420 回答
-4

对于基值(当然还有系统字体)调用GetDialogBaseUnits. 有关使用和/或不使用对话 HWNDremarks转换对话单元 <-> 像素的替代方法,另请参见段落。GetTextMetricsGetTextExtentPoint32

于 2011-07-30T11:50:16.620 回答