delphi 当Windows字体缩放比例大于100%时,如何使GUI正常工作

liwlm1x9  于 2023-01-13  发布在  Windows
关注(0)|答案(4)|浏览(1046)

当在Windows控制面板中选择大字体大小(如125%或150%)时,VCL应用程序中会出现问题,每次都会设置一些像素。
TStatusBar.Panel为例。我已经设置了它的宽度,以便它只包含一个标签,现在使用大字体的标签“溢出”。其他组件也有同样的问题。
一些新的笔记本电脑从戴尔船舶已经与125%作为默认设置,所以虽然在过去这个问题是相当罕见的,现在它是真正重要的。
可以做些什么来克服这个问题?

c90pui9n

c90pui9n1#

只要ScaledTrue,. dfm文件中的设置将正确放大。
如果您在代码中设置尺寸,则需要按Screen.PixelsPerInch除以Form.PixelsPerInch来缩放它们。请使用MulDiv来完成此操作。

function TMyForm.ScaleDimension(const X: Integer): Integer;
begin
  Result := MulDiv(X, Screen.PixelsPerInch, PixelsPerInch);
end;

ScaledTrue时,表单持久性框架就是这样做的。
事实上您可以提出一个令人信服的论据,将此函数替换为硬编码为分母值96的版本。这样,您可以使用绝对维度值,而不必担心在开发计算机上更改字体缩放比例并重新保存. dfm文件时含义会发生变化。dfm文件是上次保存. dfm文件的计算机的值。

const
  SmallFontsPixelsPerInch = 96;

function ScaleFromSmallFontsDimension(const X: Integer): Integer;
begin
  Result := MulDiv(X, Screen.PixelsPerInch, SmallFontsPixelsPerInch);
end;

因此,继续这个主题,另一件需要注意的事情是,如果您的项目是在多台DPI值不同的机器上开发的,您会发现Delphi在保存. dfm文件时使用的缩放比例会导致控件在一系列编辑中徘徊。在我工作的地方,为了避免这种情况,我们有一个严格的政策,即表单只能在96dpi(100%缩放比例)下编辑。
事实上,我的ScaleFromSmallFontsDimension版本也考虑到了运行时表单字体与设计时设置不同的可能性。在XP机器上,我的应用程序的表单使用8pt的Tahoma。在Vista和最高9pt的Segoe UI上使用。这提供了另一个自由度。缩放比例必须考虑到这一点,因为源代码中使用的绝对尺寸值被假定为相对于96dpi的8pt Tahoma基线。
如果你在你的UI中使用任何图像或字形,那么它们也需要缩放。一个常见的例子是工具栏和菜单上使用的字形。你会想要提供这些字形作为链接到你的可执行文件的图标资源。每个图标应该包含一个大小范围,然后在运行时你选择最合适的大小并将其加载到图像列表中。关于这个主题的一些细节可以在这里找到:How do I load icons from a resource without suffering from aliasing?
另一个有用的技巧是用相对单位定义尺寸,相对于TextWidthTextHeight。所以,如果你想让某个东西的大小在10条垂直线左右,你可以使用10*Canvas.TextHeight('Ag')。这是一个非常粗略和现成的度量,因为它不考虑行距等。然而,通常,您所需要做的就是能够安排GUI使用PixelsPerInch正确缩放。
你也应该把你的应用程序标记为high DPI aware。最好的方法是通过应用程序清单。因为Delphi的构建工具不允许你定制清单,所以你必须链接你自己的清单资源。

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:windowsSettings
         xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>

资源脚本如下所示:
其中Manifest.txt包含实际的清单。您还需要包含comctl32 v6部分并将requestedExecutionLevel设置为asInvoker。然后将此编译资源链接到您的应用,并确保Delphi不会尝试对其清单执行相同操作。在现代Delphi中,您可以通过将Runtime Themes项目选项设置为None来实现这一点。
manifest是声明应用具有高DPI感知能力的"正确"方式。如果你只是想快速试用而不想弄乱manifest,请调用SetProcessDPIAware。在应用运行时,首先要执行此操作。最好是在早期的单元初始化部分之一,或者作为. dpr文件中的第一项操作。
如果你不声明你的应用程序是高DPI感知的,那么Vista和更高版本将在传统模式下呈现任何字体缩放超过125%。这看起来相当可怕。尽量避免落入陷阱。

    • Windows 8.1每监视器DPI更新**

从Windows 8.1开始,操作系统支持每台显示器的DPI设置(http://msdn.microsoft.com/en-ca/magazine/dn574798.aspx)。这对于现代设备来说是个大问题,因为现代设备可能有不同的显示器,附加了非常不同的功能。你可能有一个非常高DPI的笔记本电脑屏幕,和一个低DPI的外置投影仪。支持这样的场景需要比上面描述的更多的工作。

xj3cbfub

xj3cbfub2#

注意:请参阅其他答案,因为它们包含了非常有价值的技术。我在这里的答案只提供了警告和警告,不要假设DPI感知是容易的。
我通常会避免使用TForm.Scaled = True进行DPI感知扩展。DPI感知只有在对打电话给我并愿意为此付费的客户变得重要时才对我重要。这种观点背后的技术原因是DPI感知与否,你正在打开一扇通往伤害世界的Windows。许多标准和第三方VCL控件在高DPI下不能很好地工作。值得注意的例外是, Package Windows公共控件的VCL部分在高DPI下工作得非常好。大量第三方和内置Delphi VCL自定义控件在高DPI下工作得不好,或者根本不工作。如果您计划打开TForm.Scaled,请确保在96、125、和150 dpi的每一个单一的形式在您的项目,每一个单一的第三方和内置的控制,您使用。
Delphi本身是用Delphi编写的。对于大多数窗体,它打开了High DPI感知标志,尽管就在最近的Delphi XE2中,IDE作者自己决定不打开High DPI感知清单标志。请注意,在Delphi XE4和更高版本中,HIGH DPI感知标志是打开的,IDE看起来很好。
我建议您不要将TForm.Scaled = true(这是Delphi中的默认设置,因此除非您修改了它,否则大多数表单都具有Scaled = true)与High DPI Aware标志(如David的答案所示)一起用于使用内置Delphi表单设计器构建的VCL应用程序。
我过去曾尝试过做一个最小的样本,说明当TForm. Scaled为真时,以及当Delphi表单缩放出现小故障时,您可以期望看到的那种断裂。这些小故障并不总是也不只是由96以外的DPI值触发的。我一直无法确定其他事情的完整列表,这包括windows xp字体大小的变化。但是由于大多数这些小故障只出现在我自己的应用程序中,在相当复杂的情况下,我决定向您展示一些证据,您可以验证自己。
当您在Windows 7中将DPI缩放设置为"Fonts@200%"时,Delphi XE看起来是这样的,Delphi XE2在Windows 7和8上也类似地被破坏,但这些故障似乎在Delphi XE4中得到了修复:

这些大多数是标准VCL控件,在高DPI时会出现问题。注意,大多数东西根本没有被缩放,所以Delphi IDE开发人员决定忽略DPI感知,并关闭DPI虚拟化。真是一个有趣的选择。
只有当你想要这个新的额外的痛苦来源和困难的选择时,才关闭DPI虚拟化。我建议你不要去管它。注意Windows公共控件大多数看起来工作得很好。注意Delphi数据资源管理器控件是一个标准Windows树公共控件周围的C#WinForms Package 器。这是一个纯粹的微软故障。修复它可能需要Embarcadero为他们的数据浏览器重写一个纯本地. Net树控件,或者编写一些DPI检查和修改属性代码来更改控件中的项目高度。即使是MicrosoftWinForms也不能干净地处理高DPI,自动地并且不需要定制的组装代码。
更新:有趣的事实陈述:虽然delphiIDE看起来没有被"虚拟化",但它并没有使用David所展示的清单内容来实现"非DPI虚拟化",也许它在运行时使用了一些API函数。
更新2:作为对如何支持100%/125% DPI的回应,我将提出一个两阶段的计划:第一阶段是清点需要针对高DPI进行修复的自定义控件的代码,然后制定一个计划来修复或逐步淘汰它们。第2阶段是将代码中设计为没有布局管理的窗体的部分区域转换为使用某种布局的窗体管理,以便DPI或字体高度的变化可以工作,而不裁剪。我怀疑这种"控制间"布局工作将远远超过复杂的大多数应用程序比"控制内"的工作。

    • 更新:**2016年,最新的Delphi 10. 1 Berlin在我的150 dpi工作站上运行良好。
cnh2zyt3

cnh2zyt33#

同样重要的是要注意,尊重用户的DPI只是你真正工作的一个子集:
尊重用户的字体大小
用户的DPI是字体选择的副作用。

  • 如果您尊重用户的字体大小,您将根据定义尊重他们的DPI (良好)
  • 如果您只尊重用户的DPI,您将不尊重他们的字体选择 (坏)

Windows开发人员需要停止认为遵守DPI是他们想要做的事情。你不想遵守他们的DPI。DPI不是你想要遵守的设置。如果你遵守DPI,你就做错了。
您要使用他们的字体. (影响DPI)
几十年来,Windows已经通过使用对话框单位(而不是像素)执行布局的概念解决了这个问题。定义 "对话框单位" 是为了使字体的 * 平均字符 *

  • 4个对话单位(DLU)宽,以及
  • 8个对话单位(dlus)高

Delphi确实附带了一个(有缺陷的)TCustomForm.Scaled概念,其中窗体试图根据

  • 用户的Windows DPI设置,与
  • 上次保存表单的开发人员的计算机上的DPI设置

当用户使用的字体与您设计表单时使用的字体不同时,这并不能解决问题,例如:

  • 开发人员使用MS Sans Serif 8pt(其中平均字符为6.21px x 13.00px,分辨率为96dpi)设计表单
  • 使用Tahoma 8pt(其中平均字符数为5.94px x 13.00px,分辨率为96dpi)运行的用户

任何为Windows 2000或Windows XP开发应用程序的人都是如此。

  • 开发人员使用Tahoma 8pt(其中平均字符数为5.94px x 13.00px,分辨率为96dpi)设计表单
  • 运行Segoe UI 9pt的用户(其中平均字符为6.67px x 15px,分辨率为96dpi)

使用TCustomForm.Scaled是不好的。这是一个坏主意。这是一个坏选择。这是一个坏设计。您需要在设计时将所有窗体的.Scaled设置为False
作为一名优秀的开发人员,您的目标是尊重用户的字体首选项。这意味着您还需要缩放窗体上的所有控件以匹配新的字体大小:

  • 横向扩展12.29%(6.67/5.94)
  • 纵向拉伸15.38%(15/13)

Scaled无法为您处理此问题。
在以下情况下,情况会变得更糟:

  • Segoe UI 9pt(Windows Vista、Windows 7、Windows 8默认设置)中设计了您的表单
  • 用户正在运行Segoe UI 14pt(例如,我的首选项),即10.52px x 25px

现在您必须扩展所有内容

  • 横向增长57.72%
  • 纵向增长66.66%

Scaled无法为您处理此问题。
如果你聪明的话,你会发现尊重DPI是多么的无关紧要:

  • 使用Segoe UI 9pt@96dpi(6.67px x 15px)设计的表单
  • 使用Segoe UI运行的用户,9点,150 dpi(10.52像素x 25像素)

您不应查看用户的DPI设置,而应查看他们的 * 字体大小 *。两个用户运行:

  • Segoe用户界面14磅,分辨率96 dpi(10.52像素x 25像素)
  • Segoe用户界面,9磅,分辨率为150 dpi(10.52像素x 25像素)
  • 运行相同的字体 。DPI只是影响字体大小的一个*因素;用户的偏好是另一个。

标准化表单字体

Clovis注意到我引用了一个函数StandardizeFormFont,它可以修复表单上的字体,并将其缩放到新的字体大小,它不是一个标准函数,而是一整套函数,可以完成Borland从未处理过的简单任务。

function StandardizeFormFont(AForm: TForm): Real;
var
    preferredFontName: string;
    preferredFontHeight: Integer;
begin
    GetUserFontPreference({out}preferredFontName, {out}preferredFontHeight);

    //e.g. "Segoe UI",     
    Result := Toolkit.StandardizeFormFont(AForm, PreferredFontName, PreferredFontHeight);
end;

Windows中没有单一的"字体设置",Windows有6种不同的字体:
| 字体|如何检索|
| - ------|- ------|
| 图标标题|* * 一米十一米一**|
| 标题|* * 一米十二米一x**|
| 小标题|* * 一米十三十一x**|
| 菜单|* * 一米十四分一秒**|
| 现况|* * 一米十五纳一x**|
| 信息|* * 一米十六分一秒**|
但是我们从经验中知道,我们的表单应该遵循Icon Title Font设置

procedure GetUserFontPreference(out FaceName: string; out PixelHeight: Integer);
var
   font: TFont;
begin
   font := Toolkit.GetIconTitleFont;
   try
      FaceName := font.Name; //e.g. "Segoe UI"

      //Dogfood testing: use a larger font than we're used to; to force us to actually test it    
      if IsDebuggerPresent then
         font.Size := font.Size+1;
    
      PixelHeight := font.Height; //e.g. -16
   finally
      font.Free;
   end;
end;

一旦我们知道了字体大小,我们将把表单从缩放到,我们得到表单当前的字体高度(以像素为单位),然后按这个因子放大。
例如,如果我将表单设置为**-16,并且表单当前位于-11**,则需要按以下方式缩放整个表单:

-16 / -11 = 1.45454%

标准化分两个阶段进行。首先按新旧字体大小的比例缩放窗体。然后实际更改控件(递归)以使用新字体。

function StandardizeFormFont(AForm: TForm; FontName: string; FontHeight: Integer): Real;
var
    oldHeight: Integer;
begin
    Assert(Assigned(AForm));

    if (AForm.Scaled) then
    begin
        OutputDebugString(PChar('WARNING: StandardizeFormFont: Form "'+GetControlName(AForm)+'" is set to Scaled. Proper form scaling requires VCL scaling to be disabled, unless you implement scaling by overriding the protected ChangeScale() method of the form.'));
    end;

    if (AForm.AutoScroll) then
    begin
        if AForm.WindowState = wsNormal then
        begin
            OutputDebugString(PChar('WARNING: StandardizeFormFont: Form "'+GetControlName(AForm)+'" is set to AutoScroll. Form designed size will be suseptable to changes in Windows form caption height (e.g. 2000 vs XP).'));
                    if IsDebuggerPresent then
                        Windows.DebugBreak; //Some forms would like it (to fix maximizing problem)
        end;
    end;

    if (not AForm.ShowHint) then
    begin
        AForm.ShowHint := True;
        OutputDebugString(PChar('INFORMATION: StandardizeFormFont: Turning on form "'+GetControlName(AForm)+'" hints. (ShowHint := True)'));
                    if IsDebuggerPresent then
                        Windows.DebugBreak; //Some forms would like it (to fix maximizing problem)
    end;

    oldHeight := AForm.Font.Height;

    //Scale the form to the new font size
//  if (FontHeight <> oldHeight) then    For compatibility, it's safer to trigger a call to ChangeScale, since a lot of people will be assuming it always is called
    begin
        ScaleForm(AForm, FontHeight, oldHeight);
    end;

    //Now change all controls to actually use the new font
    Toolkit.StandardizeFont_ControlCore(AForm, g_ForceClearType, FontName, FontHeight,
            AForm.Font.Name, AForm.Font.Size);

    //Return the scaling ratio, so any hard-coded values can be multiplied
    Result := FontHeight / oldHeight;
end;

下面是实际缩放表单的工作。它解决了Borland自己的Form.ScaleBy方法中的bug。首先,它必须禁用表单上的所有锚点,然后执行缩放,再重新启用锚点:

TAnchorsArray = array of TAnchors;

procedure ScaleForm(const AForm: TForm; const M, D: Integer);
var
    aAnchorStorage: TAnchorsArray;
    RectBefore, RectAfter: TRect;
    x, y: Integer;
    monitorInfo: TMonitorInfo;
    workArea: TRect;
begin
    if (M = 0) and (D = 0) then
        Exit;

    RectBefore := AForm.BoundsRect;

    SetLength(aAnchorStorage, 0);
    aAnchorStorage := DisableAnchors(AForm);
    try
        AForm.ScaleBy(M, D);
    finally
        EnableAnchors(AForm, aAnchorStorage);
    end;

    RectAfter := AForm.BoundsRect;

    case AForm.Position of
    poScreenCenter, poDesktopCenter, poMainFormCenter, poOwnerFormCenter,
    poDesigned: //i think i really want everything else to also follow the nudging rules...why did i exclude poDesigned
        begin
            //This was only nudging by one quarter the difference, rather than one half the difference
//          x := RectAfter.Left - ((RectAfter.Right-RectBefore.Right) div 2);
//          y := RectAfter.Top - ((RectAfter.Bottom-RectBefore.Bottom) div 2);
            x := RectAfter.Left - ((RectAfter.Right-RectAfter.Left) - (RectBefore.Right-RectBefore.Left)) div 2;
            y := RectAfter.Top - ((RectAfter.Bottom-RectAfter.Top)-(RectBefore.Bottom-RectBefore.Top)) div 2;
        end;
    else
        //poDesigned, poDefault, poDefaultPosOnly, poDefaultSizeOnly:
        x := RectAfter.Left;
        y := RectAfter.Top;
    end;

    if AForm.Monitor <> nil then
    begin
        monitorInfo.cbSize := SizeOf(monitorInfo);
        if GetMonitorInfo(AForm.Monitor.Handle, @monitorInfo) then
            workArea := monitorInfo.rcWork
        else
        begin
            OutputDebugString(PChar(SysErrorMessage(GetLastError)));
            workArea := Rect(AForm.Monitor.Left, AForm.Monitor.Top, AForm.Monitor.Left+AForm.Monitor.Width, AForm.Monitor.Top+AForm.Monitor.Height);
        end;

//      If the form is off the right or bottom of the screen then we need to pull it back
        if RectAfter.Right > workArea.Right then
            x := workArea.Right - (RectAfter.Right-RectAfter.Left); //rightEdge - widthOfForm

        if RectAfter.Bottom > workArea.Bottom then
            y := workArea.Bottom - (RectAfter.Bottom-RectAfter.Top); //bottomEdge - heightOfForm

        x := Max(x, workArea.Left); //don't go beyond left edge
        y := Max(y, workArea.Top); //don't go above top edge
    end
    else
    begin
        x := Max(x, 0); //don't go beyond left edge
        y := Max(y, 0); //don't go above top edge
    end;

    AForm.SetBounds(x, y,
            RectAfter.Right-RectAfter.Left, //Width
            RectAfter.Bottom-RectAfter.Top); //Height
end;

然后我们必须递归地使用新字体

procedure StandardizeFont_ControlCore(AControl: TControl; ForceClearType: Boolean;
        FontName: string; FontSize: Integer;
        ForceFontIfName: string; ForceFontIfSize: Integer);
const
    CLEARTYPE_QUALITY = 5;
var
    i: Integer;
    RunComponent: TComponent;
    AControlFont: TFont;
begin
    if not Assigned(AControl) then
        Exit;

    if (AControl is TStatusBar) then
    begin
        TStatusBar(AControl).UseSystemFont := False; //force...
        TStatusBar(AControl).UseSystemFont := True;  //...it
    end
    else
    begin
        AControlFont := Toolkit.GetControlFont(AControl);

        if not Assigned(AControlFont) then
            Exit;

        StandardizeFont_ControlFontCore(AControlFont, ForceClearType,
                FontName, FontSize,
                ForceFontIfName, ForceFontIfSize);
    end;

{   If a panel has a toolbar on it, the toolbar won't paint properly. So this idea won't work.
    if (not Toolkit.IsRemoteSession) and (AControl is TWinControl) and (not (AControl is TToolBar)) then
        TWinControl(AControl).DoubleBuffered := True;
}

    //Iterate children
    for i := 0 to AControl.ComponentCount-1 do
    begin
        RunComponent := AControl.Components[i];
        if RunComponent is TControl then
            StandardizeFont_ControlCore(
                    TControl(RunComponent), ForceClearType,
                    FontName, FontSize,
                    ForceFontIfName, ForceFontIfSize);
    end;
end;

在递归禁用锚点的情况下:

function DisableAnchors(ParentControl: TWinControl): TAnchorsArray;
var
    StartingIndex: Integer;
begin
    StartingIndex := 0;
    DisableAnchors_Core(ParentControl, Result, StartingIndex);
end;

procedure DisableAnchors_Core(ParentControl: TWinControl; var aAnchorStorage: TAnchorsArray; var StartingIndex: Integer);
var
    iCounter: integer;
    ChildControl: TControl;
begin
    if (StartingIndex+ParentControl.ControlCount+1) > (Length(aAnchorStorage)) then
        SetLength(aAnchorStorage, StartingIndex+ParentControl.ControlCount+1);

    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        aAnchorStorage[StartingIndex] := ChildControl.Anchors;

        //doesn't work for set of stacked top-aligned panels
//      if ([akRight, akBottom ] * ChildControl.Anchors) <> [] then
//          ChildControl.Anchors := [akLeft, akTop];

        if (ChildControl.Anchors) <> [akTop, akLeft] then
            ChildControl.Anchors := [akLeft, akTop];

//      if ([akTop, akBottom] * ChildControl.Anchors) = [akTop, akBottom] then
//          ChildControl.Anchors := ChildControl.Anchors - [akBottom];

        Inc(StartingIndex);
    end;

    //Add children
    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        if ChildControl is TWinControl then
            DisableAnchors_Core(TWinControl(ChildControl), aAnchorStorage, StartingIndex);
    end;
end;

并且锚被递归地重新启用:

procedure EnableAnchors(ParentControl: TWinControl; aAnchorStorage: TAnchorsArray);
var
    StartingIndex: Integer;
begin
    StartingIndex := 0;
    EnableAnchors_Core(ParentControl, aAnchorStorage, StartingIndex);
end;

procedure EnableAnchors_Core(ParentControl: TWinControl; aAnchorStorage: TAnchorsArray; var StartingIndex: Integer);
var
    iCounter: integer;
    ChildControl: TControl;
begin
    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        ChildControl.Anchors := aAnchorStorage[StartingIndex];

        Inc(StartingIndex);
    end;

    //Restore children
    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        if ChildControl is TWinControl then
            EnableAnchors_Core(TWinControl(ChildControl), aAnchorStorage, StartingIndex);
    end;
end;

实际更改控件字体的工作留给:

procedure StandardizeFont_ControlFontCore(AControlFont: TFont; ForceClearType: Boolean;
        FontName: string; FontSize: Integer;
        ForceFontIfName: string; ForceFontIfSize: Integer);
const
    CLEARTYPE_QUALITY = 5;
var
    CanChangeName: Boolean;
    CanChangeSize: Boolean;
    lf: TLogFont;
begin
    if not Assigned(AControlFont) then
        Exit;

{$IFDEF ForceClearType}
    ForceClearType := True;
{$ELSE}
    if g_ForceClearType then
        ForceClearType := True;
{$ENDIF}

    //Standardize the font if it's currently
    //  "MS Shell Dlg 2" (meaning whoever it was opted into the 'change me' system
    //  "MS Sans Serif" (the Delphi default)
    //  "Tahoma" (when they wanted to match the OS, but "MS Shell Dlg 2" should have been used)
    //  "MS Shell Dlg" (the 9x name)
    CanChangeName :=
            (FontName <> '')
            and
            (AControlFont.Name <> FontName)
            and
            (
                (
                    (ForceFontIfName <> '')
                    and
                    (AControlFont.Name = ForceFontIfName)
                )
                or
                (
                    (ForceFontIfName = '')
                    and
                    (
                        (AControlFont.Name = 'MS Sans Serif') or
                        (AControlFont.Name = 'Tahoma') or
                        (AControlFont.Name = 'MS Shell Dlg 2') or
                        (AControlFont.Name = 'MS Shell Dlg')
                    )
                )
            );

    CanChangeSize :=
            (
                //there is a font size
                (FontSize <> 0)
                and
                (
                    //the font is at it's default size, or we're specifying what it's default size is
                    (AControlFont.Size = 8)
                    or
                    ((ForceFontIfSize <> 0) and (AControlFont.Size = ForceFontIfSize))
                )
                and
                //the font size (or height) is not equal
                (
                    //negative for height (px)
                    ((FontSize < 0) and (AControlFont.Height <> FontSize))
                    or
                    //positive for size (pt)
                    ((FontSize > 0) and (AControlFont.Size <> FontSize))
                )
                and
                //no point in using default font's size if they're not using the face
                (
                    (AControlFont.Name = FontName)
                    or
                    CanChangeName
                )
            );

    if CanChangeName or CanChangeSize or ForceClearType then
    begin
        if GetObject(AControlFont.Handle, SizeOf(TLogFont), @lf) <> 0 then
        begin
            //Change the font attributes and put it back
            if CanChangeName then
                StrPLCopy(Addr(lf.lfFaceName[0]), FontName, LF_FACESIZE);
            if CanChangeSize then
                lf.lfHeight := FontSize;

            if ForceClearType then
                lf.lfQuality := CLEARTYPE_QUALITY;
            AControlFont.Handle := CreateFontIndirect(lf);
        end
        else
        begin
            if CanChangeName then
                AControlFont.Name := FontName;
            if CanChangeSize then
            begin
                if FontSize > 0 then
                    AControlFont.Size := FontSize
                else if FontSize < 0 then
                    AControlFont.Height := FontSize;
            end;
        end;
    end;
end;

这比你想象的要多得多我知道。可悲的是,地球上没有Delphi开发人员,除了我,我实际上使他们的应用程序正确。

    • 尊敬的Delphi开发人员**:将Windows字体设置为Segoe UI 14pt,并修复有缺陷的应用程序
    • 注**:任何代码都将被发布到公共领域。不需要归属。
rjjhvcjd

rjjhvcjd4#

这是我的礼物。一个可以帮助你在GUI布局中水平定位元素的函数。对所有人免费。

function CenterInParent(Place,NumberOfPlaces,ObjectWidth,ParentWidth,CropPercent: Integer): Integer;
  {returns formated centered position of an object relative to parent.
  Place          - P order number of an object beeing centered
  NumberOfPlaces - NOP total number of places available for object beeing centered
  ObjectWidth    - OW width of an object beeing centered
  ParentWidth    - PW width of an parent
  CropPercent    - CP percentage of safe margin on both sides which we want to omit from calculation
  +-----------------------------------------------------+
  |                                                     |
  |        +--------+       +---+      +--------+       |
  |        |        |       |   |      |        |       |
  |        +--------+       +---+      +--------+       |
  |     |              |             |            |     |
  +-----------------------------------------------------+
  |     |<---------------------A----------------->|     |
  |<-C->|<------B----->|<-----B----->|<-----B---->|<-C->|
  |                    |<-D>|
  |<----------E------------>|

  A = PW-C   B = A/NOP  C=(CP*PW)/100  D = (B-OW)/2
  E = C+(P-1)*B+D }

var
  A, B, C, D: Integer;
begin
  C := Trunc((CropPercent*ParentWidth)/100);
  A := ParentWidth - C;
  B := Trunc(A/NumberOfPlaces);
  D := Trunc((B-ObjectWidth)/2);
  Result := C+(Place-1)*B+D;
end;

相关问题