如何让视觉继承在高 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
的组件进行了两次缩放,但这并没有什么坏处,因为原始大小和位置被记住为缩放的基值,结果完全相同。
我有以下示例表单 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 的 - 但由于
FReserved
中的值,缩放不适用于派生形式的组件
dfm
文件
因此,一种想法是在读取组件之前重置缓存的 DPI
值。它对 Form1
的组件进行了两次缩放,但这并没有什么坏处,因为原始大小和位置被记住为缩放的基值,结果完全相同。