Search code examples
delphihighdpi

Delphi and High-DPI: Controls created on runtime obtain wrong position


I have a problem with positioning of controls created at runtime in a High-DPI application. For instance, I've created a Label and would like to create an Image and position it directly to the right of the label.

if USER_EMAIL <> '' then
begin
  lblSummary_Email := TcxLabel.Create(pnlSummary);
  with lblSummary_Email do
  begin
    Caption := 'E-Mail: ' + USER_EMAIL;
    Top := 125;
    Left := 278;
    AutoSize := true;
    Parent := pnlSummary;
  end;

  with TcxImage.Create(pnlSummary) do
  begin
    Width := 17;
    Height := 17;
    Top := lblSummary_Email .Top;
    Left := lblSummary_Email .Left + lblSummary_Email .Width + 10;
    Picture := imgConfirmed.Picture;
    Properties.ShowFocusRect := false;
    Style.BorderStyle := ebsNone;
    Enabled := false;
    Parent := pnlSummary;
  end;
end;

The image is positioned incorrectly. This suggests that the position I set at runtime will be converted directly to High-DPI. How to avoid this or how to set correct position for the runtime created controls in High-DPI applications?


Solution

  • When you create a component during runtime, it is created at 96 DPI.

    The assignment of Parent to a control will scale the position/size to conform with that parent's DPI.

    So you set the Left/Top at 96 DPI (100%) pixel coordinates, and at the assignment of Parent, it gets converted to (say) 150% pixel coordinates.

    So to solve your issue, you should assign Parent before you set the bounds of the control:

    if USER_EMAIL <> '' then
    begin
      lblSummary_Email := TcxLabel.Create(pnlSummary);
      with lblSummary_Email do
      begin
        Parent := pnlSummary;
        Caption := 'E-Mail: ' + USER_EMAIL;
        Top := 125;
        Left := 278;
        AutoSize := true;
      end;
    
      with TcxImage.Create(pnlSummary) do
      begin
        Parent := pnlSummary;
        Width := 17;
        Height := 17;
        Top := lblSummary_Email .Top;
        Left := lblSummary_Email .Left + lblSummary_Email .Width + 10;
        Picture := imgConfirmed.Picture;
        Properties.ShowFocusRect := false;
        Style.BorderStyle := ebsNone;
        Enabled := false;
      end;
    end;
    

    The move of Parent assignment of the label to before positioning it depends on whether the coords you assign should be scaled (if so, leave it where you had it), or be absolute (ie. always at (278,175) pixel coordinates irrespectively of scaling).