I'm using Delphi 10.4.1 Sydney, and have created a simple control which has its Parent
set at runtime:
constructor TMyTree.Create(AOwner: TComponent);
begin
inherited Create(Owner);
PopupMenu := TPopupMenu.Create(Self);
end;
procedure TMyTree.ChangeScale(M, D: Integer; isDpiChange: boolean);
begin
inherited ChangeScale(M, D, isDpiChange);
OutputDebugString(PChar(Format('M: %d, D: %d', [M, D])));
//The program is started at 150% DPI and DPI changed to 175% DPI
//Debug Output: M: 168, D: 96 - ERROR! It should be M: 168, D: 144
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
fTree := TMyTree.Create(Self);
fTree.Parent := Self;
OutputDebugString(PChar(Format('CurrentPPI: %d', [fTree.CurrentPPI])));
//Debug Output at 150% DPI scale: CurrentPPI: 144 - OK!
end;
The problem is that ChangeScale()
is called with wrong parameters by VCL (see the comments in the code).
I think that is caused by the fact that when PopupMenu := TPopupMenu.Create(Self);
is called in the TMyTree
constructor, the tree's ComponentState
is set by VCL to [csFreeNotification]
.
I have inspected the VCL code, more specifically TControl.SetParent()
. If csFreeNotification
is in ComponentState
then ScaleForPPI
is NOT called, and our tree view is not scaled when its Parent
is set.
Is this a bug in the VCL, or there is some other preferred way to create runtime controls and set their Parent
?
By the way, the same issue happens if I use TImageList.Create(Self)
in the TMyTree
constructor.
This is a known issue in the VCL. There are several tickets reported in Quality Portal related to it:
RSP-18162: Frame with Assigned PopupMenu is wrong Displayed on high DPI
RSP-19012: Parented controls with free notifications aren't scaled