7

I would like to use a TFontDialog with Delphi 10.3.3 on a high dpi monitor.

But unfortunately Delphi does not really scale the content. (Check where the example (Beispiel) is positioned!)

I have 2 monitors. The primary has 96ppi, the other one 144ppi. My application is running on the second one.

How did you solve such a problem in your applications? Is there a way to fix that or do I have to hope that Delphi 10.4 will solve this problem?

With 200% and higher you cannot read the font size anymore.

enter image description here

Edit (2020-01-13):

All depends on the DPI-awareness set whithin of Delphi:

None, Unaware & Systemaware:

FontDialog has a size of 648x518 pixel, everything is positioned well but is blur

Per Monitor:

FontDialog has a size of 433x346 pixel and is too small (100%)

Per Monitor V2:

FontDialog has a size of 648x528 pixel, everything is sharp but not correct (see image)

Jens
  • 347
  • 1
  • 12
  • 2
    You should enable the DPI awareness of your app. If you need a multi monitor UI with different DPI values, use the "per monitor" awareness. Here is a link to get some information about this on Windows platform: https://learn.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows – The Bitman Jan 10 '20 at 12:44
  • DPI-Awareness is set to "per Monitor V2" via Delphi manifest. – Jens Jan 10 '20 at 13:13
  • Does the issue appear in debug mode or run as an exe, too? If just in the previous case then set the DPI awareness on the launching icon of Delphi RAD Studio. (Right click, Properties, Compatibility, Change high DPI Settings) – The Bitman Jan 10 '20 at 17:01
  • 3
    `TFontDialog` is just a wrapper for the Win32 [`ChooseFont()`](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms646914(v%3Dvs.85)) API, so any DPI issues in the dialog are on the part of the OS itself, not in the VCL. – Remy Lebeau Jan 10 '20 at 17:51
  • 1
    @Jens When opening the dialog using `FontDialog.Execute` do you pass your forms windows handle as a parameter to the execute call like `FontDialog1.Execute(Form1.Handle)` for example? Not sure but I'm guessing this would be required so that Dialog can retrieve correct DPI resolution of the monitor on which it was opened. – SilverWarior Jan 11 '20 at 16:55
  • @TheBitman: The problems appears in debug and release mode. – Jens Jan 13 '20 at 07:38
  • @SilverWarior: I tried that also before. But it does not change the behaviour. – Jens Jan 13 '20 at 07:39
  • @RemyLebeau: So I have to hope that Microsoft will solve this? Win10 is out for how many years? Is there really hope for it? Do you use your own FontDialog or none at all? – Jens Jan 13 '20 at 07:46
  • 1
    @SilverWarior if an HWND is not passed to Execute(), it uses the HWND of the currently active Form. – Remy Lebeau Jan 13 '20 at 08:17
  • @RemyLebeau: I edited the original post. The problem appears only with a manifest with a dpi-awareness of PM v2. Doesn't this mean that Delphi is adjusting the component? – Jens Jan 13 '20 at 08:29
  • @Jens no, because the actual dialog is created and managed by the OS, not by the VCL. – Remy Lebeau Jan 13 '20 at 15:30
  • Have you tried fixes from RRUZ: https://github.com/RRUZ/vcl-styles-utils – Darian Miller Feb 24 '20 at 19:47

1 Answers1

1

Unfortunately TFontDialog, or to be exact the underlying ChooseFont from Windows, does not (yet) support per Monitor V2 DPI awareness. As a workaround you can temporarily switch to System aware while the dialog is displayed and switch back afterwards.

To implement this I suggest a interposer class that overrides TFontDialog:

type
  TFontDialog = class(Vcl.Dialogs.TFontDialog)
  protected
    function TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool; override;
  end;

function TFontDialog.TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
var
  previousDpiContext: DPI_AWARENESS_CONTEXT;
begin
  previousDpiContext := SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
  try
    Result := inherited TaskModalDialog(DialogFunc, DialogData);
  finally
    SetThreadDpiAwarenessContext(previousDpiContext);
  end;
end;

Note that the font size given to and retrieved from from the dialog is based on system DPI and has to be scaled from/to the monitor DPI it is used.

Uwe Raabe
  • 45,288
  • 3
  • 82
  • 130