Delphi:处理用户字体首选项

11
我想到了一个调用方法,可以获取用户界面字体偏好(与Borland硬编码的选择“MS Sans Serif”不同)。
假设用户的字体偏好是:
Segoe Print, 15pt

我将所有应用程序中所有表单上的所有项目的字体设置为:

Segoe Print, 15pt

问题在于现在的东西被截断了。按钮太小 - 太窄、太短。标签中的文本被剪切等。
这个表单有一个"Scaled"属性,但它不会随着字体大小的改变而改变。当数字"0"的高度改变时,该属性会根据序列化后的表单进行缩放。
我找不到任何有关Borland如何支持用户Windows应用程序首选项的帮助信息。
我该如何处理用户字体首选项?
注意:我从Embargadero的新闻组服务器转帖过来,因为Embargadero的新闻服务器似乎正在死亡、审查、损坏或要求登录。
更新1:
我谈论的是用户的字体首选项,而不是DPI设置。例如:想象一下以下的语言中立伪代码:
procedure TForm1.FormCreate(Sender: TObject);
var
    FontFace: string;
    FontHeight: Integer;
begin
    GetUserFontPreference(out FontFace, out FontHeight);
    Self.Font.Name := FontFace;
    Self.Font.Height := FontHeight;
end;

注意:这不是我的实际代码(毕竟这是语言中立的伪代码)。但是,您需要递归地遍历表单上的每个控件,在需要更改字体时进行更改。当一个字体应用了与其父级不同的样式(例如加粗),并且不再从其父级继承时,需要手动设置。


根据lkessler的要求,以下是从Windows检索用户UI字体首选项的代码:

procedure GetUserFontPreference(out FaceName: string; out PixelHeight: Integer);
var
    lf: LOGFONT;
begin
    ZeroMemory(@lf, SizeOf(lf));
     //Yes IconTitleFont (not SPI_GETNONCLIENTMETRICS MessageFont)
    if SystemParametersInfo(SPI_GETICONTITLELOGFONT, SizeOf(lf), @lf, 0) then
    begin
        FaceName := PChar(Addr(lf.lfFaceName[0]));
        PixelHeight := lf.lfHeight;
    end
    else
    begin
        {
            If we can't get it, then assume the same non-user preferences that
            everyone else does.
        }
        FaceName := 'MS Shell Dlg 2';
        PixelHeight := 8;
    end;
end;

相关问题


我很好奇,你使用的是哪个调用来获取用户界面字体偏好设置? - lkessler
我会在原问题中更新代码。 - Ian Boyd
不同的字体或不同的DPI设置 - 它们有什么区别,为什么需要调整控件大小和位置?适应用户字体偏好需要在运行时计算控件的大小和位置,就像不同的DPI设置一样。 - mghie
但正如我在我的回答中所说 - 或许Jordan Russell的代码可以帮助你。只需按用户字体的平均字符宽度和高度与MS Sans Serif 8(或表单设计时使用的任何字体)的比率成比例地缩放所有表单即可。 - mghie
为什么是IconTitleFont而不是MessageFont? - Uli Gerhardt
显示剩余2条评论
6个回答

9

首先,让我们明确一下,Borland不再拥有Delphi。现在Embarcadero拥有Delphi,我们现在是在安全的、可靠的手中。

好的,接下来回答你的问题。

诀窍是将TForm.AutoScroll设置为False,并确保您的开发机器设置为小字体。TForm.Scaled保持不变(它的默认值为True)。

这就是我们在内部所做的,IDE处理一切都很好。


据我所知,IDE 并没有完美地处理所有事情。在我的笔记本电脑屏幕上(设置为 124 DPI),Delphi 2007 对象检查器中的所有行都被截断了... - mghie
让开发人员“确保您的开发机器设置为小字体”并不构成我书中的诡计。这要么是无知,要么就是虐待狂。试试在145 DPI显示器上使用小字体... - mghie
你没有仔细阅读问题,假设不同的DPI设置。我说的是不同的字体。为了这个问题的目的,让我们假设世界上每台机器都设置为96dpi。 - Ian Boyd
Embarcadero现在拥有Delphi,我们现在可以放心,安全地交付了。我会等待10年才同意。 - Ian Boyd

3
我理解你的感受。但是公正地说:VCL所采用的基于像素的布局机制无法创建适当的GUI布局。需要的是动态布局引擎,该引擎仅在以下情况下布置控件:
1.为每个控件设置适当的字体(这取决于Windows版本、用户偏好以及控件类型)。
2.将控件中的文本翻译成当前语言环境,因为这可能会增加或减少控件所需的空间。
由于所有这些都取决于运行时属性,因此通过放置控件来创建对话框是行不通的。GTK和QT的布局机制或wxWidgets中的sizers更适合此类任务。
我不知道Delphi程序是否有这样的东西。在某些程序中,我会在设置字体和翻译文本后手动调整控件的大小和位置。虽然需要很多工作,但根据你的受众而定,这可能值得一试。
你还可以查看Jordan Russell为Inno Setup编写的代码。他没有使用窗体的缩放属性,而是编写了自定义控件缩放的代码。也许它也适用于高DPI屏幕上非常大的字体;我注意到在我的124 DPI笔记本电脑屏幕上设置对话框看起来相当不错。

1
我不同意。DLUs的概念非常好。Microsoft在WinForms中几乎做到了,但错过了一些关键点,所以它和Borlands一样糟糕。 - Ian Boyd
当a)不同的控件使用不同的字体(如Vista上); b)文本长度将随着翻译而在运行时更改; 以及c)需要使用布局引擎在运行时调整对话框大小时,使用DLU是无效的。有些布局引擎支持这三个功能。DLU无济于事。 - mghie
a) DLUs随字体缩放(如Vista上) b) 我从未写过除英语以外的任何东西 c) - Ian Boyd
Vista为不同的控件使用不同的字体(请参见http://msdn.microsoft.com/en-us/library/aa511282.aspx),因此它们需要相应地进行缩放。这将是哪个DLU?但是让我们停止这个话题,它真的没有任何进展。 - mghie

3

我喜欢使用这个函数。它基于Graphics.GetFontData。

procedure SystemFont(Font: TFont);
var
  LogFont: TLogFont;
begin
  if SystemParametersInfo(SPI_GETICONTITLELOGFONT, SizeOf(TLogFont), @LogFont, 0) then
    begin
      Font.Height := LogFont.lfHeight;
      Font.Orientation := LogFont.lfOrientation;
      Font.Charset := TFontCharset(LogFont.lfCharSet);
      Font.Name := PChar(@LogFont.lfFaceName);

      Font.Style := [];

      if LogFont.lfWeight >= FW_BOLD then
        Font.Style := Font.Style + [fsBold];

      if LogFont.lfItalic = 1 then
        Font.Style := Font.Style + [fsItalic];

      if LogFont.lfUnderline = 1 then
        Font.Style := Font.Style + [fsUnderline];

      if LogFont.lfStrikeOut = 1 then
        Font.Style := Font.Style + [fsStrikeOut];

      case LogFont.lfPitchAndFamily and $F of
        VARIABLE_PITCH: Font.Pitch := fpVariable;
        FIXED_PITCH: Font.Pitch := fpFixed;
        else Font.Pitch := fpDefault;
      end;
    end;
end;

您只需在所有TForm.OnCreate事件上使用它即可。另一种方法是创建一个新类,在创建或循环屏幕表单时执行此操作。
如果更改表单上任何控件的默认字体属性,则它们仍将使用旧字体。如果您想在某些控件上使用自定义属性,则需要在调用SystemFont之后进行调整。
在运行时更改Graphics.DefFontData可能有所帮助,如果表单设计器只将更改的属性写入.dfm文件中。

这并没有解决非标准字体可能会使控件中的文本过大,从而需要调整大小和重新定位的问题。 - mghie
我正要说同样的话。我没有问题获取默认字体,问题是“处理用户的字体偏好”。 - Ian Boyd

2
要做好这件事,我认为您需要:
1- 加载用户的字体偏好设置
2- 按照您所描述的应用它
3- 确定所有标题的宽度和高度(以像素为单位),并将其与控件的宽度和高度进行比较,并相应地进行调整。
不幸的是,“相应地进行调整”部分很难。您可以扩大按钮的宽度,但那样您就必须检查它是否与另一个控件重叠。
您最好的选择可能是创建略微超大的控件,并希望用户不选择32点字体大小。

1
:( <- 表示悲伤的表情,这段文字只是为了让评论足够长,以便StackOverflow接受我的两个字符评论作为有效评论。 - Ian Boyd

1

Kogus有正确的想法,但漏掉了你需要使用的函数。这将是Windows GetTextExtentPoint32例程。你传递给它一个字符串,它会使用当前选择的字体计算字符串的宽度和高度。你可以在Windows.pas中找到它。

你可能想提前计算出允许使用的字体所需的最大空间。

或者你可以使用该函数动态调整显示文本区域的大小,使其适合文本。

这对于一个或两个控件来说很好,但如果你试图在整个用户界面上做到这一点,任何一种方法都需要大量的工作。


0
我认为这有点像翻译。在我们的应用程序中,我们将按钮、标签、编辑等所有元素都稍微放大了一点,以便一些语言需要更长的单词时可以轻松容纳。这并不会影响设计。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接