I have the following example form TForm1
with two buttons (BitBtn
):
Additionally I have a second form TForm2
which is derived from the first form.
The second button is moved to the left and another button is added:
At runtime (Windows 7), the second form looks like this:
If I change font scaling to 125%, my form looks like this:
Somehow, the new button has the wrong position and the wrong size. What can I do about this?
I used the following .dfm
files (shortened):
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 files are left unchanged as the designer generates them. They contain no relevant code.
I found a possible solution myself: one has to overwrite ReadState
with
the following code:
procedure TForm2.ReadState(Reader: TReader);
begin
IntPtr(FReserved) := 0;
inherited;
end;
This looks strange. How does it work?
I looked at the VCL
source code and found
that scaling after form loading is done in TForm.ReadState(...)
. Apparrently, a protected
field FReserved
of TControl
is used to store the currently applied DPI
value:
dfm
are readDPI
value is stored in FReserved
ReadState
is called again, for the dfm
file of the derived classFReserved
, scaling is not applied to components of the derived formSo, one idea would be to reset the cached DPI
value before reading the components. It scales the components of Form1
twice, but this doesn't hurt as the original sizes and positions are remembered as base value for scaling and the result is exactly the same.