Difference between revisions of "High DPI"

From Free Pascal wiki
Jump to navigationJump to search
m (→‎STEP 2 - Scale Forms and Controls: simplified procedure)
(48 intermediate revisions by 11 users not shown)
Line 1: Line 1:
 
{{High DPI}}
 
{{High DPI}}
  
== Definition ==
+
== Introduction ==
DPI (dot per inch) is the relation between size in pixels and the actual display size. Here dot is an equivalent for pixel in printing terminology. Applications can either use pixel sizes, or take into account that actual display size. In this second cases, sizes are given in points.
 
  
On Windows Vista and further, it is possible to change the DPI ratio to make elements bigger. High DPI means any custom DPI setting with more than 96 DPI (the default setting) [http://msdn.microsoft.com/en-us/library/ee318406(VS.85).aspx *].
+
DPI (Dots Per Inch) is the relation between size in pixels and the actual display size. Here dot is an equivalent for pixel in printing terminology. Applications can either use pixel sizes, or take into account the actual display size. In this second case, sizes are given in points.
 +
 
 +
Most of today operating systems use default DPI set to 96 and allow to change it to higher value manually. The physical DPI can be determined from display through [http://en.wikipedia.org/wiki/Extended_display_identification_data EDID] protocol from physical size data and actual resolution. But the physical DPI is not used automatically by system so if you connect video output to monitor with different size then sceen resolution and visual size of controls are not automatically changed.
 +
 
 +
Usually DPI is presented as one value but it can be different for horizontal and vertical axes if pixel is not square.
 +
 
 +
In addition to basic application DPI awareness you can add own DPI options to your application to allow users to set custom per application DPI to overcome wrong system DPI setting.
 +
 
 +
===Lazarus DPI related properties===
 +
* Graphics.ScreenInfo.PixelsPerInchX
 +
* Graphics.ScreenInfo.PixelsPerInchY
 +
* Forms.Screen.PixelsPerInch
 +
* Forms.TForm.DesignTimePPI (See: [http://wiki.lazarus.freepascal.org/Autosize_/_Layout#DPI_auto-adjustment_and_absolute_layout_auto-adjustment DPI auto-adjustment and absolute layout auto-adjustment])
  
High DPI awareness means that an application takes this DPI setting into account.
 
  
== Pixels and points ==
+
===Pixels and points===
  
For example 300 DPI means that there are 300 pixels (or dot) per inch. There are 72 points per inch, so :
+
For example '''300 DPI''' means that there are 300 pixels (or dots) per inch. There are 72 points per inch, so :
  
 
300 pixels ↔ 1 inch
 
300 pixels ↔ 1 inch
Line 18: Line 28:
 
4.16 pixels ↔ 1 point
 
4.16 pixels ↔ 1 point
  
 +
'''Now with 96 DPI :'''
  
Now with 96 DPI :
+
96 pixels ↔ 1 inch
 
 
72 pixels ↔ 1 inch
 
  
 
1.33 pixel ↔ 1 point
 
1.33 pixel ↔ 1 point
  
 
+
'''Now with 144 DPI :'''
Now with 144 DPI :
 
  
 
144 pixels ↔ 1 inch
 
144 pixels ↔ 1 inch
Line 32: Line 40:
 
2 pixels ↔ 1 point
 
2 pixels ↔ 1 point
  
== Setting High DPI in Windows ==
+
== Setting High DPI ==
In Windows 7 go to Control Panel > Appareance and Personalization > Display.
 
  
Select Smaller 100% (default), Medium 125% or Larger 150%. If you select 100% (96 DPI) is the default Windows DPI setting, not High DPI.
+
=== Windows ===
  
If you select 125% (120 DPI) the option "Use Windows XP style DPI scaling" is enabled, applications you run under this setting are scaled like at Windows XP.
+
On Windows 95 and later, it is possible to change the DPI ratio to make elements bigger. High DPI means any custom DPI setting with more than 96 DPI (the default setting) [http://msdn.microsoft.com/en-us/library/ee318406(VS.85).aspx *].
  
If you select 150% (144 DPI) the option "Use Windows XP style DPI scaling" is disabled (DPI Virtualization enabled), applications you run under this setting must be High DPI Awareness else they will be scaled by the system like a blurred image.
+
High DPI awareness means that an application takes this DPI setting into account.
  
Also you can set your custom DPI setting in the option "Set custom text size (DPI)" and enable/disable the DPI Virtualization.
+
==== Windows Vista and Windows 7 ====
  
== Example ==
+
In Windows 7 go to "Control Panel > Appearance and Personalization > Display" (or just Control Panel > Display in recent updates).
  
Here is a form with an undefined font size (set to zero, which is the default value). Designed in 96 DPI (100%), it looks like this :
+
Select Smaller 100% (default), Medium 125% or Larger 150%. If you select 100% (96 DPI) this is the default Windows DPI setting, (High DPI is not the default).
  
[[Image:Testdpi100.png]]
+
If you select 125% (120 DPI) the option "Use Windows XP style DPI scaling" is enabled. Applications you run under this setting are scaled as if running under Windows XP.
  
Now, with 120 DPI (125%), it becomes :
+
If you select 150% (144 DPI) the option "Use Windows XP style DPI scaling" is disabled (DPI Virtualization is enabled), and applications you run under this setting must be High DPI Awareness to prevent system scaling which will produce a blurred image.
  
[[Image:Testdpi125.png]]
+
You can also set your custom DPI setting via the option "Set custom text size (DPI)" and enable/disable the DPI Virtualization.
  
As you can see, the font gets bigger and clipped, the window title gets bigger, but the client area of the window keeps the same size. Note that these change of size can occur by using an application with different windows theme, or with another operating system.
+
==== Windows 8 Metro Applications ====
  
To avoid this, set the font size to a non-zero value. Note that Font.Size is expressed in points and Font.Height is expressed in pixels. In fact, the value of Font.Height only is stored, and Font.Size changes according to current DPI value. So if we set the font size, it will be fixed to a certain size in pixels.
+
For Windows 8 Metro Applications read this http://blogs.msdn.com/b/b8/archive/2012/03/21/scaling-to-different-screens.aspx
  
If we try again with a fixed font size of 9 points in 96 DPI (100%), we get this :
+
==== Windows 10 ====
  
[[Image:Testdpi100fixedM12P9.png]]
+
Windows 10 "Control Panel > Appearance and Personalization > Display" have more options. You can have different font sizes for each element: Title bar, Menu, Dialog box and so on. Ensure you test twice in order to check if everything works under different sizes.
  
Now if the same program is run in 120 DPI (125%), it becomes :
+
Now is based on Font Size, not DPI. The DPI option is not recommended, but still there. So, instead of changing the size of all elements in desktop, this will change just the font size (And of course everything else is changed to fit).
  
[[Image:Testdpi125fixedM12P9.png]]
+
Remember that under Windows 10 there are Universal Applications (WinRT) and the classic desktop applications (Win32). We're talking here about desktop applications.
  
The result is the almost the same. The title bar is bigger, but the client area and the font size is the same. Note that in fact, the size in points of the font has changed.
+
=== Linux ===
  
As a conclusion, it is possible to avoid inconsistence in the display by fixing font sizes. But we do not take into account that the graphical elements may be smaller according to actual DPI of the screen. With DPI awareness, it is possible to make application behave as if they new the real size of the pixels.
+
On Linux DPI setting is more complicated and depends on used software and their version.  
  
== Example (Windows) ==
+
You can discover your current monitor DPI by command:
 +
<syntaxhighlight lang="bash">xdpyinfo|grep dots </syntaxhighlight>
  
[http://sourceforge.net/projects/cpicksniff2/ CPickSniff] is an application to capture screen colors. We will use it as an example to see how High DPI works in Windows.
+
You can change DPI to new value by command:
 +
<syntaxhighlight lang="bash">xrandr --dpi 144x144</syntaxhighlight>
  
=== Default DPI ===
+
To preserve setting after reboot you need to add the command as script to /etc/X11/Xsession.d/77set_dpi.
  
This is the app running at 96 DPI (100%). It's the default mode, when scaling isn't necessary.
+
More information:
 +
* [http://askubuntu.com/questions/197828/how-to-find-and-change-the-screen-dpi How to find and change the screen DPI?]
 +
* [https://wiki.archlinux.org/index.php/xorg#Display_size_and_DPI Xorg Display size and DPI]
 +
* [https://help.ubuntu.com/community/AsusZenbook#LCD Change fixed 96dpi on Ubuntu with high DPI LCD]
  
[[Image:cpicksniff_defaultdpi.png]]
+
== Examples ==
  
=== Windows DPI Scaling ===
+
=== Fixed Font Sizes (not HighDPI) ===
  
This is same app running at 144 DPI (150%) without manifest, so Windows scales it like a bitmap. The result is a blurred image.
+
Here is a form with an undefined font size (set to zero, which is the default value). It has been designed at 96 DPI (100%), and it looks like this :
  
[[Image:cpicksniff_blured.png]]
+
[[Image:Testdpi100.png]]
  
=== With Manifest ===
+
Now, at 120 DPI (125%), it becomes :
  
Running at 144 DPI (150%). This time the app includes manifest but the application contains no code to handle scaling. Items aren't scaled whereas font are scaled (Windows does it automatically), so text is clipped.
+
[[Image:Testdpi125.png]]
  
[[Image:cpicksniff_nohighdpi.png]]
+
As you can see, the font gets bigger and so the text is clipped. The window title gets bigger, but the client area of the window remains the same size. Note that these changes in size can occur by using an application with a different Windows theme, or with another operating system.
  
=== High DPI ===
+
To avoid this, you must set the font size to a non-zero value. Note that Font.Size is expressed in points and Font.Height is expressed in pixels. In fact, only the value of Font.Height is stored, and Font.Size changes according to current DPI value. So if we set the font size, it will be fixed to a certain size in pixels.
  
Finally with manifest and scaling handler, the app is in High DPI.
+
If we try again with a fixed font size of 9 points, then at 96 DPI (100%), we get this :
  
[[Image:cpicksniff_highdpi.png]]
+
[[Image:Testdpi100fixedM12P9.png]]
  
== High DPI in Lazarus ==
+
Now if the same program is run at 120 DPI (125%), it becomes :
  
With Lazarus we have to follow 2 steps in order to make an High DPI Awareness application for Windows 7.
+
[[Image:Testdpi125fixedM12P9.png]]
  
=== STEP 1 - Declare High DPI Awareness ===
+
The result is the almost the same. The title bar is bigger, but the client area and the font size is the same. Note that in fact, the size in points of the font has changed.
To do this we need a manifest file that includes the declaration, with Lazarus 0.9.30 we can do this going to Options > Project Options > then select the options "Use Manifest to Enable Themes (Windows)" and "Dpi Aware application (for Vista +)".
 
  
=== STEP 2 - Scale Forms and Controls ===
+
The conclusion from this is that it is possible to avoid inconsistency in the display by fixing font sizes. But we do not take into account that the graphical elements may be smaller according to actual DPI of the screen. With DPI awareness, it is possible to make an application behave as if it knew the real size of the pixels.
To do this we can call ScaleDPI procedure OnCreate event of each form in your project.
 
  
First copy the below code and save to a text file "uscaledpi.pas":
 
  
<delphi>unit uscaledpi;
+
=== DPI Aware Application (For Vista +) ===
  
{$mode objfpc}{$H+}
+
[http://sourceforge.net/projects/cpicksniff2/ CPickSniff] is an application to capture screen colors. We will use it as an example to see how High DPI works in Windows.
  
interface
+
'''Default DPI'''
  
uses
+
This is the app running at 96 DPI (100%). It's the default mode, when scaling isn't necessary.
  Forms, Graphics, Controls;
 
  
procedure HighDPI(FromDPI: integer);
+
[[Image:cpicksniff_defaultdpi.png]]
procedure ScaleDPI(Control: TControl; FromDPI: integer);
 
  
implementation
+
'''Windows DPI Scaling'''
  
procedure HighDPI(FromDPI: integer);
+
This is the same app running at 144 DPI (150%) without a manifest, so Windows scales it like a bitmap. The result is a blurred image.
var
 
  i: integer;
 
begin
 
  if Screen.PixelsPerInch = FromDPI then
 
    exit;
 
  
  for i := 0 to Screen.FormCount - 1 do
+
[[Image:cpicksniff_blured.png]]
    ScaleDPI(Screen.Forms[i], FromDPI);
 
end;
 
  
procedure ScaleDPI(Control: TControl; FromDPI: integer);
+
'''With Manifest'''
var
 
  i: integer;
 
  WinControl: TWinControl;
 
begin
 
  if Screen.PixelsPerInch = FromDPI then
 
    exit;
 
  
  with Control do
+
Running at 144 DPI (150%). This time the app includes a manifest but the application contains no code to handle scaling. Items aren't scaled whereas fonts are scaled (Windows does this automatically), so text is clipped.
  begin
 
    Left := ScaleX(Left, FromDPI);
 
    Top := ScaleY(Top, FromDPI);
 
    Width := ScaleX(Width, FromDPI);
 
    Height := ScaleY(Height, FromDPI);
 
  end;
 
  
  if Control is TWinControl then
+
[[Image:cpicksniff_nohighdpi.png]]
  begin
 
    WinControl := TWinControl(Control);
 
    if WinControl.ControlCount = 0 then
 
      exit;
 
    for i := 0 to WinControl.ControlCount - 1 do
 
      ScaleDPI(WinControl.Controls[i], FromDPI);
 
  end;
 
end;
 
  
end.</delphi>
+
'''High DPI'''
  
Copy the "uscaledpi.pas" file to the main folder of your project:
+
Finally with both a manifest and a LCL scaling, the app is in High DPI.
  
  MyProject\uscaledpi.pas
+
[[Image:cpicksniff_highdpi.png]]
 
 
In the "uses" section of your project you need to add "uScaleDPI":
 
 
 
<delphi>unit form1;
 
 
 
{$mode objfpc}{$H+}
 
 
 
interface
 
 
 
uses
 
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
 
  uScaleDPI; // This includes ScaleDPI procedure </delphi>
 
 
 
The OnCreate event of each form calls the procedure in this way:
 
 
 
<delphi>procedure TForm1.FormCreate(Sender: TObject);
 
begin
 
  ScaleDPI(Self,96); // 96 is the DPI you designed the Form1 
 
end;</delphi>
 
 
 
=== Scale All Forms ===
 
 
 
You can change the step 2 to scale all forms.
 
 
 
In order to do this open your project source (typically the ''Project1''.lpr file) and add uScaleDPI in the uses clause.
 
 
 
Then call the procedure ''HighDPI'' below the code that initializes the forms:
 
 
 
<delphi>begin
 
  RequireDerivedFormResource := True;
 
  Application.Initialize;
 
  Application.CreateForm(TForm1, Form1);
 
  Application.CreateForm(TForm2, Form2);
 
  Application.CreateForm(TForm3, Form3);
 
  HighDPI(96);  // 96 is the DPI you designed the Form1, Form2 & Form3
 
  Application.Run;
 
end.</delphi>
 
 
 
The result looks like this:
 
 
 
<delphi>program Project1;
 
 
 
{$mode objfpc}{$H+}
 
 
 
uses
 
  {$IFDEF UNIX}{$IFDEF UseCThreads}
 
  cthreads,
 
  {$ENDIF}{$ENDIF}
 
  Interfaces, Forms,
 
  Unit1, Unit2, Unit3,
 
  uScaleDPI;
 
 
 
{$R *.res}
 
 
 
begin
 
  RequireDerivedFormResource := True;
 
  Application.Initialize;
 
  Application.CreateForm(TForm1, Form1);
 
  Application.CreateForm(TForm2, Form2);
 
  Application.CreateForm(TForm3, Form3);
 
  HighDPI(96);
 
  Application.Run;
 
end.</delphi>
 
 
 
=== Advanced ===
 
 
 
Some controls have more properties or different property names like TToolBar buttons (ButtonHeight / ButtonWidth instead Width / Height). Also if you use fixed font sizes the behavior can change in different os's.
 
 
 
You can edit the ScaleDPI procedure to include a code to scale all controls in the way you want.
 
 
 
This is the ''uscaledpi'' used in [[LazPaint]]. This is very usefull to scale ToolBars and ToolBox. Also LazPaint uses fixed fonts to be consistent in different os's.
 
 
 
But this is not the final High DPI unit, for example you can use under Windows different LCL widgets, like Qt and this can change the final result.
 
 
 
<delphi>unit uscaledpi;
 
 
 
{$mode objfpc}{$H+}
 
 
 
interface
 
 
 
uses
 
  Forms, Graphics, Controls, ComCtrls;
 
 
 
procedure HighDPI(FromDPI: Integer);
 
procedure ScaleDPI(Control: TControl; FromDPI: Integer);
 
procedure ScaleImageList(ImgList: TImageList; FromDPI: Integer);
 
 
 
implementation
 
 
 
uses BGRABitmap, BGRABitmapTypes;
 
 
 
procedure HighDPI(FromDPI: Integer);
 
var
 
  i: Integer;
 
begin
 
  for i:=0 to Screen.FormCount-1 do begin
 
    ScaleDPI(Screen.Forms[i],FromDPI);
 
  end;
 
end;
 
 
 
procedure ScaleImageList(ImgList: TImageList; FromDPI: Integer);
 
var
 
  TempBmp: TBitmap;
 
  TempBGRA: array of TBGRABitmap;
 
  NewWidth,NewHeight: integer;
 
  i: Integer;
 
 
 
begin
 
  if Screen.PixelsPerInch = FromDPI then exit;
 
 
 
  NewWidth := ScaleX(ImgList.Width,FromDPI);
 
  NewHeight := ScaleY(ImgList.Height,FromDPI);
 
 
 
  setlength(TempBGRA, ImgList.Count);
 
  TempBmp := TBitmap.Create;
 
  for i := 0 to ImgList.Count-1 do
 
  begin
 
    ImgList.GetBitmap(i,TempBmp);
 
    TempBGRA[i] := TBGRABitmap.Create(TempBmp);
 
    TempBGRA[i].ResampleFilter := rfBestQuality;
 
    if (TempBGRA[i].width=0) or (TempBGRA[i].height=0) then continue;
 
    while (TempBGRA[i].Width < NewWidth) or (TempBGRA[i].Height < NewHeight) do
 
      BGRAReplace(TempBGRA[i], TempBGRA[i].FilterSmartZoom3(moLowSmooth));
 
    BGRAReplace(TempBGRA[i], TempBGRA[i].Resample(NewWidth,NewHeight));
 
  end;
 
  TempBmp.Free;
 
 
 
  ImgList.Clear;
 
  ImgList.Width:= NewWidth;
 
  ImgList.Height:= NewHeight;
 
 
 
  for i := 0 to high(TempBGRA) do
 
  begin
 
    ImgList.Add(TempBGRA[i].Bitmap,nil);
 
    TempBGRA[i].Free;
 
  end;
 
end;
 
 
 
procedure ScaleDPI(Control: TControl; FromDPI: Integer);
 
var
 
  n: Integer;
 
  WinControl: TWinControl;
 
  ToolBarControl: TToolBar;
 
begin
 
  if Screen.PixelsPerInch = FromDPI then exit;
 
 
 
  with Control do begin
 
    Left:=ScaleX(Left,FromDPI);
 
    Top:=ScaleY(Top,FromDPI);
 
    Width:=ScaleX(Width,FromDPI);
 
    Height:=ScaleY(Height,FromDPI);
 
    {$IFDEF LCL Qt}
 
      Font.Size := 0;
 
    {$ELSE}
 
      Font.Height := ScaleY(Font.GetTextHeight('Hg'),FromDPI);
 
    {$ENDIF}
 
  end;
 
 
 
  if Control is TToolBar then begin
 
    ToolBarControl:=TToolBar(Control);
 
    with ToolBarControl do begin
 
      ButtonWidth:=ScaleX(ButtonWidth,FromDPI);
 
      ButtonHeight:=ScaleY(ButtonHeight,FromDPI);
 
    end;
 
  end;
 
 
 
  if Control is TWinControl then begin
 
    WinControl:=TWinControl(Control);
 
    if WinControl.ControlCount > 0 then begin
 
      for n:=0 to WinControl.ControlCount-1 do begin
 
        if WinControl.Controls[n] is TControl then begin
 
          ScaleDPI(WinControl.Controls[n],FromDPI);
 
        end;
 
      end;
 
    end;
 
  end;
 
end;
 
 
 
end.    </delphi>
 
 
 
== Conclusion ==
 
  
Making your application aware of DPI settings and themes includes two steps :
+
== High DPI in Lazarus 1.8 and above ==
* Set a fixed font size at design time (Usefull for cross-platform applications, if your target is only Windows isn't neccesary)
 
* Scale components at run time
 
* Improve the ScaleDPI code to your needs
 
  
'''NOTE:'''
+
To handle High DPI using new features in 1.8, follow these steps:
  
See Discussion page for more information: [[Talk:High_DPI]].
+
* On Windows: enable DPI awareness in Project Options -> Application. Decide if you want to support per monitor DPI awareness or not.
 +
* Enable LCL scaling for your application DPI awareness in Project Options -> Application -> "Use LCL scaling (Hi-DPI).
 +
* Set TForm.Scaled=True for all your forms (it is the default value). All WYSIWYG should work automatically. Also the designer scales the forms accordingly.
 +
* If you create controls run-time, scale all coordinates, sizes etc that have to be DPI-aware with TControl.Scale96ToForm() or ScaleDesignToForm() (depending on your choice of default PPI) or prepare your container (e.g. panel with controls) as it was with 96 PPI and then call TControl.AutoAdjustLayout(lapAutoAdjustForDPI, 96, ParentFormOfTheContainer.PixelsPerInch, 0, 0);
 +
* If some of your components don't scale their inner sizes, override DoAutoAdjustLayout and scale the sizes (see TToolBar) - it has to be done for all controls. If a LCL control misses DoAutoAdjustLayout please report to mantis and provide a patch if you can.
  
I'm NOT using ScaleBy & ScaleControls:
+
=== Lazarus IDE high DPI ===
  
<delphi>Self.ScaleBy(Screen.PixelsPerInch,96);</delphi>
+
The Lazarus IDE is DPI-aware itself.
  
This scales the font, in Windows isn't neccesary because the OS changes font. May be usefull if you use fixed font size.
+
== High DPI in older Lazarus ==
  
<delphi>Self.ScaleControls(Screen.PixelsPerInch,96);</delphi>
+
Is not as nice as 1.8 but it works, call on each form OnCreate event:
  
This doesn't scales form width / height. May be usefull if you scale those by yourself.
+
Self.AutoAdjustLayout(lapAutoAdjustForDPI, 96, Screen.PixelsPerInch, Self.Width, ScaleX(Self.Width, 96));
  
 
== External Links ==
 
== External Links ==
  
*[http://msdn.microsoft.com/en-us/library/dd464646(v=VS.85).aspx High DPI (Windows)] MSDN article about High DPI
+
* [http://msdn.microsoft.com/en-us/library/dd464646(v=VS.85).aspx High DPI (Windows)] MSDN article about High DPI
*[[Windows Icon]] How to create icons that work with High DPI.
+
* [http://msdn.microsoft.com/en-us/library/windows/apps/hh465362 Guidelines for scaling] Windows Dev Center - User experience guidelines for scaling Metro style apps
[[Category:Tutorials]]
+
* [[Windows Icon]] How to create icons that work with High DPI.

Revision as of 18:15, 23 May 2018

Deutsch (de) English (en) español (es) русский (ru)

Introduction

DPI (Dots Per Inch) is the relation between size in pixels and the actual display size. Here dot is an equivalent for pixel in printing terminology. Applications can either use pixel sizes, or take into account the actual display size. In this second case, sizes are given in points.

Most of today operating systems use default DPI set to 96 and allow to change it to higher value manually. The physical DPI can be determined from display through EDID protocol from physical size data and actual resolution. But the physical DPI is not used automatically by system so if you connect video output to monitor with different size then sceen resolution and visual size of controls are not automatically changed.

Usually DPI is presented as one value but it can be different for horizontal and vertical axes if pixel is not square.

In addition to basic application DPI awareness you can add own DPI options to your application to allow users to set custom per application DPI to overcome wrong system DPI setting.

Lazarus DPI related properties


Pixels and points

For example 300 DPI means that there are 300 pixels (or dots) per inch. There are 72 points per inch, so :

300 pixels ↔ 1 inch

300/72 pixels ↔ 1 point

4.16 pixels ↔ 1 point

Now with 96 DPI :

96 pixels ↔ 1 inch

1.33 pixel ↔ 1 point

Now with 144 DPI :

144 pixels ↔ 1 inch

2 pixels ↔ 1 point

Setting High DPI

Windows

On Windows 95 and later, it is possible to change the DPI ratio to make elements bigger. High DPI means any custom DPI setting with more than 96 DPI (the default setting) *.

High DPI awareness means that an application takes this DPI setting into account.

Windows Vista and Windows 7

In Windows 7 go to "Control Panel > Appearance and Personalization > Display" (or just Control Panel > Display in recent updates).

Select Smaller 100% (default), Medium 125% or Larger 150%. If you select 100% (96 DPI) this is the default Windows DPI setting, (High DPI is not the default).

If you select 125% (120 DPI) the option "Use Windows XP style DPI scaling" is enabled. Applications you run under this setting are scaled as if running under Windows XP.

If you select 150% (144 DPI) the option "Use Windows XP style DPI scaling" is disabled (DPI Virtualization is enabled), and applications you run under this setting must be High DPI Awareness to prevent system scaling which will produce a blurred image.

You can also set your custom DPI setting via the option "Set custom text size (DPI)" and enable/disable the DPI Virtualization.

Windows 8 Metro Applications

For Windows 8 Metro Applications read this http://blogs.msdn.com/b/b8/archive/2012/03/21/scaling-to-different-screens.aspx

Windows 10

Windows 10 "Control Panel > Appearance and Personalization > Display" have more options. You can have different font sizes for each element: Title bar, Menu, Dialog box and so on. Ensure you test twice in order to check if everything works under different sizes.

Now is based on Font Size, not DPI. The DPI option is not recommended, but still there. So, instead of changing the size of all elements in desktop, this will change just the font size (And of course everything else is changed to fit).

Remember that under Windows 10 there are Universal Applications (WinRT) and the classic desktop applications (Win32). We're talking here about desktop applications.

Linux

On Linux DPI setting is more complicated and depends on used software and their version.

You can discover your current monitor DPI by command:

xdpyinfo|grep dots

You can change DPI to new value by command:

xrandr --dpi 144x144

To preserve setting after reboot you need to add the command as script to /etc/X11/Xsession.d/77set_dpi.

More information:

Examples

Fixed Font Sizes (not HighDPI)

Here is a form with an undefined font size (set to zero, which is the default value). It has been designed at 96 DPI (100%), and it looks like this :

Testdpi100.png

Now, at 120 DPI (125%), it becomes :

Testdpi125.png

As you can see, the font gets bigger and so the text is clipped. The window title gets bigger, but the client area of the window remains the same size. Note that these changes in size can occur by using an application with a different Windows theme, or with another operating system.

To avoid this, you must set the font size to a non-zero value. Note that Font.Size is expressed in points and Font.Height is expressed in pixels. In fact, only the value of Font.Height is stored, and Font.Size changes according to current DPI value. So if we set the font size, it will be fixed to a certain size in pixels.

If we try again with a fixed font size of 9 points, then at 96 DPI (100%), we get this :

Testdpi100fixedM12P9.png

Now if the same program is run at 120 DPI (125%), it becomes :

Testdpi125fixedM12P9.png

The result is the almost the same. The title bar is bigger, but the client area and the font size is the same. Note that in fact, the size in points of the font has changed.

The conclusion from this is that it is possible to avoid inconsistency in the display by fixing font sizes. But we do not take into account that the graphical elements may be smaller according to actual DPI of the screen. With DPI awareness, it is possible to make an application behave as if it knew the real size of the pixels.


DPI Aware Application (For Vista +)

CPickSniff is an application to capture screen colors. We will use it as an example to see how High DPI works in Windows.

Default DPI

This is the app running at 96 DPI (100%). It's the default mode, when scaling isn't necessary.

cpicksniff defaultdpi.png

Windows DPI Scaling

This is the same app running at 144 DPI (150%) without a manifest, so Windows scales it like a bitmap. The result is a blurred image.

cpicksniff blured.png

With Manifest

Running at 144 DPI (150%). This time the app includes a manifest but the application contains no code to handle scaling. Items aren't scaled whereas fonts are scaled (Windows does this automatically), so text is clipped.

cpicksniff nohighdpi.png

High DPI

Finally with both a manifest and a LCL scaling, the app is in High DPI.

cpicksniff highdpi.png

High DPI in Lazarus 1.8 and above

To handle High DPI using new features in 1.8, follow these steps:

  • On Windows: enable DPI awareness in Project Options -> Application. Decide if you want to support per monitor DPI awareness or not.
  • Enable LCL scaling for your application DPI awareness in Project Options -> Application -> "Use LCL scaling (Hi-DPI).
  • Set TForm.Scaled=True for all your forms (it is the default value). All WYSIWYG should work automatically. Also the designer scales the forms accordingly.
  • If you create controls run-time, scale all coordinates, sizes etc that have to be DPI-aware with TControl.Scale96ToForm() or ScaleDesignToForm() (depending on your choice of default PPI) or prepare your container (e.g. panel with controls) as it was with 96 PPI and then call TControl.AutoAdjustLayout(lapAutoAdjustForDPI, 96, ParentFormOfTheContainer.PixelsPerInch, 0, 0);
  • If some of your components don't scale their inner sizes, override DoAutoAdjustLayout and scale the sizes (see TToolBar) - it has to be done for all controls. If a LCL control misses DoAutoAdjustLayout please report to mantis and provide a patch if you can.

Lazarus IDE high DPI

The Lazarus IDE is DPI-aware itself.

High DPI in older Lazarus

Is not as nice as 1.8 but it works, call on each form OnCreate event:

Self.AutoAdjustLayout(lapAutoAdjustForDPI, 96, Screen.PixelsPerInch, Self.Width, ScaleX(Self.Width, 96));

External Links