Search code examples
delphidpi

DPI scaling runtime created controls having PopupMenu


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.


Solution

  • This is a known issue in the VCL. There are several tickets reported in Quality Portal related to it:

    RSP-15381: A scaled form gets resized to design time ClientWidth/ClientHeight when embeded in a parent form

    RSP-18162: Frame with Assigned PopupMenu is wrong Displayed on high DPI

    RSP-19012: Parented controls with free notifications aren't scaled