Microsoft 在其 UI 指南中使用对话长度单位 (DLU)。如何将它们转换为像素?
据我所知,DLU 取决于系统字体大小。你能建议一些在 Delphi for Win32 中进行这种转换的简单方法吗?
Microsoft 在其 UI 指南中使用对话长度单位 (DLU)。如何将它们转换为像素?
据我所知,DLU 取决于系统字体大小。你能建议一些在 Delphi for Win32 中进行这种转换的简单方法吗?
首先我们从什么是对话单元开始。
为此,我将引用我自己未回答的问题之一:
什么是对话单元?
对话框是基于用户首选字体大小的度量单位。定义一个对话单元,使平均字符为 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;
注意:任何代码都会发布到公共领域。无需归属。
您应该使用该MapDialogRect()
功能。
RECT
以对话单位传入 a ,并RECT
返回以像素为单位的等价物。请注意,您需要对话句柄才能提供MapDialogRect()
足够的上下文。该函数需要知道字体才能执行转换。
如果您想使用GetDialogBaseUnits()
,请记住 Raymond Chen 所说的,GetDialogBaseUnits 是一个缸。
您可以从这篇文章的标题中猜到,GetDialogBaseUnits 是个垃圾。由于 GetDialogBaseUnits 没有 HWND 参数,因此它不知道您要检索哪个对话框的 DLU。所以它猜测。
而且它总是猜错。
GetDialogBaseUnits 返回使用默认系统字体的对话框的对话框基本单位。但是没有人再使用默认的系统字体了。它尖叫着“又老又笨”。但出于兼容性原因,它仍然是默认设置。(因此 GetDialogBaseUnits 也是如此。)
如果您必须从 DLU 计算像素尺寸,并且您没有对话框的句柄,那么您必须使用此处概述的方法:如何使用非基于系统的字体计算对话框基本单位
但是,您在评论中明确表示,对于您的问题,您实际上不需要从 DLU 转换为像素。您可以使用 Delphi 内置的表单缩放来确保您的表单的大小适合流行的字体缩放。
这是用于转换 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);
对于基值(当然还有系统字体)调用GetDialogBaseUnits
. 有关使用和/或不使用对话 HWNDremarks
转换对话单元 <-> 像素的替代方法,另请参见段落。GetTextMetrics
GetTextExtentPoint32