High DPI & anchoring in Delphi 11

Hello Folks!

After watching Ray Konopka’s brilliant presentation on Leveraging High DPI in VCL Applications, we thought it is time to move our project to Delphi 11 and use TImageContainer and TVirtualImageList components. Our customer suggested to use the Google icons that are available in different resolutions under the Apache License scheme.

The icons are scaling well in toolbars, bit buttons and Delphi’s own DB navigator. What we did not expect but are witnessing is problems with right anchored labels. Right anchored controls move nicely to the new DPI setting of the second screen and back to the original 96 dpi of the first screen. But labels move out and not back. The second screen is set to of 150% scaling.

The source code is available for download from here.
For those not having Delphi 11 the executable is available for download from here.

If I move the label into a panel, align the label left and the panel to the right it is working too.

At this stage it seems I need to calculate the left position of the right aligned label each time TFrom.OnAfterMonitorDpiChanged is triggered. That can’t be true.

Any ideas how to trick Delphi into doing the right thing?

Salut,
Mathias

Interesting. If you right justify alignment it does work as expected…

Hello David,

we need labels right aligned in panels and in front of controls. If they only move out but are never moved back to where they were we need to calculate their position manually each time the user moves the application to another monitor with a different DPI value.

Left aligned labels work as expected (e.g. get bigger and shrink again). In our example code the label “Current DPI: 96” is such a label.

Salut,
Mathias

Here are the screenshots for the test application:
Original96dpi

Moved to the second screen with 150% scaling:

Back at the original screen:
BackAt96DPI

This is my result with your exe.

96DPI

As expected.

144DPI

Right anchored label extends past the form.

Back to 96DPI

All good. This is with the label text left justified.

With the label text right justified this all works properly:

96DPI

144DPI

Back to 96DPI

These results differ from yours. First screen is 1920x1089 100%, second is 3840x2160 150%.

Are you using D11 or D11.1? I’m on D11.1.

Hello Dave,

I am using Delphi 11.1 build 28.0.44500.8973 .

I have changed the alignment of the label lblDPICopy to taRightJustify. The problem persists.

My first screen is a 24 inch monitor with a resolution of 1920x1200 and a scaling of 100%. The second screen is a 24 inch monitor with a resolution of 1920x1200 and a scaling of 150%. I am currently waiting for a 4K monitor to be delivered.

Salut,
Mathias

When I move the form back to screen 1 it looks like this:
MoveBackOnce

When I move it back the second time it looks like this:
MoveBackTwice

So the “Right anchored Current DPI: 96” disappears steadily.

Salut,
Mathias

Sure looks like a bug; suggest logging it in Quality Portal asap

https://quality.embarcadero.com/secure/Dashboard.jspa

Thanks, Eivind, for the suggestion.
Done (see also here).

1 Like

One more screenshot with additional logging as suggested by the ADUG Melbourne meeting attendees.
Moving to 144 dpi, back to 96 dpi, into 144 dpi and back into 96 dpi.

This is a combination of AutoSize=True, Anchors=[akTop, akRight], Alignment=taRightJustify AND changing the caption of the label during TForm.OnAfterMonitorDpiChanged.

It all seems a bit too much for the “poor label”. Nevertheless it should work correctly.

Labels with static text will be OK.

I can hear @vincent muttering under his breath from here :laughing:

1 Like

@vincent and the rest, feel free to vote here:
https://quality.embarcadero.com/browse/RSP-38692

Every time it comes back to 96 it halves, which may be correct? … but going to 144 … :woozy_face:

:roll_eyes: Yep, every day.

BTW, the issue with the values changing when moving back and forth is due to the use of integers and rounding - and that’s a windows thing. It could be circumvented by storing the base values… so if when a form first opens you store the dpi and size - then when the form is moved and then back again (without changing the size) you just use those stored values rather than the scaled values. If the form is resized on the other monitor/dpi - then you store those as the base values. It’s been proposed before but I can’t find the QC entry for it.

There also issues with font scaling. High DPI is still a long way from solved in Delphi.

I can’t replicate your problem. The code works fine for me going from a 150% FHD to a 100% FHD to a 4k 100% 240dpi screen. I am on Delphi 11.1.

DPI=240, Left=979, Top=30, Width=546
DPI=120, Left=488, Top=15, Width=273
DPI=96, Left=403, Top=12, Width=205
DPI=120, Left=489, Top=15, Width=273
DPI=240, Left=982, Top=30, Width=546
DPI=96, Left=403, Top=12, Width=205
DPI=120, Left=489, Top=15, Width=273
DPI=240, Left=982, Top=30, Width=546
DPI=96, Left=403, Top=12, Width=205
DPI=120, Left=489, Top=15, Width=273
DPI=240, Left=982, Top=30, Width=546
DPI=96, Left=403, Top=12, Width=205
DPI=120, Left=489, Top=15, Width=273
DPI=144, Left=583, Top=18, Width=330
DPI=96, Left=403, Top=12, Width=205
DPI=144, Left=584, Top=18, Width=330
DPI=240, Left=981, Top=30, Width=546
DPI=96, Left=403, Top=12, Width=205
DPI=144, Left=584, Top=18, Width=330
DPI=96, Left=402, Top=12, Width=205
DPI=144, Left=583, Top=18, Width=330
DPI=96, Left=402, Top=12, Width=205
DPI=144, Left=583, Top=18, Width=330
DPI=240, Left=980, Top=30, Width=546

Sometimes it matters which dpi the form initially opens on, and it also matters what dpi settings in the IDE and which monitor the IDE is open on. There are a lot of variables at play.

Hi,

It seems likely to be very rare that you would change the text in a caption in the the OnAfterMonitorDPI changed.

Can you trigger the change to the caption (eg. via timer, postmessage, etc) in OnAfterMonitorDPI so it happens a bit later, (eg. after the label has been relocated)

@Mathias something else to try if you have a form with lots controls with anchors or align etc (ie most forms!)


TMainForm = class(TForm)
    procedure WMDpiChanged(var Message: TWMDpi); message WM_DPICHANGED;
end;

implementation

// Attemping to improve performance when moving between monitors
procedure TMainForm.WMDpiChanged(var Message: TWMDpi);
begin
  SendMessage(Self.Handle, WM_SETREDRAW, NativeUInt(False), 0);
  try
    inherited;
  finally
    SendMessage(Self.Handle, WM_SETREDRAW, NativeUInt(true), 0);
    RedrawWindow(Self.Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_ALLCHILDREN);
  end;
end;

```
This stops the multiple redraws that happen as you drag forms across to different monitors - in my case it was really slow - finalbuilder's main form has a bunch of docked panels which use anchors heavily. 

YMMV

I am using a virtual machine for development with a 96 dpi monitor (the new 4K monitor only arrived today). The VCL Designer High DPI mode has been set to Low DPI (96 PPI). The monitor, on which I start the application, is also a 96 dpi screen. But the second screen has been set to 150% scaling, which brings it up to 144 dpi.

Anyhow our problem is kind of solved as we do not change our right anchored labels when the monitor is changed to one with higher/lower DPI value. We only do it once on start-up of the frame when we have to load localisation settings and amend captions. E.g. the department for looking after orphan children was called DoCS, then FaCS, then DCJ in NSW and maybe called totally different in other jurisdictions. Welcome to reinventing the wheel each time a government changes. :wink:

Salut,
Mathias