如何让视觉继承在高 dpi 值下工作?

How can I get visual inheritance working at high dpi values?

我有以下示例表单 TForm1 和两个按钮 (BitBtn):

此外,我还有第二种形式 TForm2,它源自第一种形式。 第二个按钮向左移动,并添加另一个按钮:

在运行时(Windows 7),第二种形式如下所示:

如果我将字体缩放比例更改为 125%,我的表单将如下所示:

不知何故,新按钮的位置和大小都不对。 我该怎么办?

我使用了以下 .dfm 个文件(缩写):

object Form1: TForm1
  Left = 0
  Top = 0
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object BitBtn1: TBitBtn
    Left = 8
    Top = 8
    Width = 105
    Height = 105
    Caption = 'BitBtn1'
  end
  object BitBtn2: TBitBtn
    Left = 359
    Top = 8
    Width = 105
    Height = 105
    Caption = 'BitBtn2'
  end
end

inherited Form2: TForm2
  Caption = 'Form2'
  PixelsPerInch = 96
  TextHeight = 13
  inherited BitBtn2: TBitBtn
    Left = 191
    Top = 7
    ExplicitLeft = 191
    ExplicitTop = 7
  end
  object BitBtn3: TBitBtn
    Left = 359
    Top = 8
    Width = 105
    Height = 104
    Caption = 'BitBtn3'
  end
end

Class 文件在设计器生成时保持不变。它们不包含相关代码。

我自己找到了一个可能的解决方案:必须用 ReadState 覆盖 以下代码:

procedure TForm2.ReadState(Reader: TReader);
begin
  IntPtr(FReserved) := 0;
  inherited;
end;    

这看起来很奇怪。它是如何工作的?

我查看了VCL源代码,发现 表单加载后的缩放在 TForm.ReadState(...) 中完成。显然,一个受保护的 TControl的字段FReserved用于存储当前应用的DPI值:

  • 首先,我的基地class dfm的所有组件都被读取
  • 然后它们被正确缩放和定位
  • 并且当前应用的DPI值存储在FReserved
  • 之后再次调用ReadState,用于派生class
  • dfm文件
  • 但由于 FReserved 中的值,缩放不适用于派生形式的组件

因此,一种想法是在读取组件之前重置缓存的 DPI 值。它对 Form1 的组件进行了两次缩放,但这并没有什么坏处,因为原始大小和位置被记住为缩放的基值,结果完全相同。