High DPI

From Lazarus wiki
Revision as of 21:34, 2 April 2011 by Lainz (talk | contribs)
Jump to navigationJump to search

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

Definition

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) *.

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

Pixels and points

For example 300 DPI means that there are 300 pixels (or dot) 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 :

72 pixels ↔ 1 inch

1.33 pixel ↔ 1 point


Now with 144 DPI :

144 pixels ↔ 1 inch

2 pixels ↔ 1 point

Setting High DPI in Windows

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.

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.

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.

Also you can set your custom DPI setting in the option "Set custom text size (DPI)" and enable/disable the DPI Virtualization.

Example

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 :

Testdpi100.png

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

Testdpi125.png

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.

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.

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

Testdpi100fixedM12P9.png

Now if the same program is run in 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.

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.

Example (Windows)

CPickSniff is an application to capture screen colors, is usefull to see how High DPI works in Windows.

Default DPI

This is the app running at 96 DPI (100%), without scaling because isn't neccesary.

cpicksniff defaultdpi.png

Windows DPI Scaling

This is same app running at 144 DPI (150%) without manifest, so Windows scale this, result: the app is scaled like a blured image.

cpicksniff blured.png

With Manifest

Running at 144 DPI (150%). This time the app includes manifest but isn't scaled, result: items aren't scaled and are smaller than expected, some clipped.

cpicksniff nohighdpi.png

High DPI

Finally with manifest and scaling, the app is High DPI.

cpicksniff highdpi.png

High DPI in Lazarus

With Lazarus we have to follow those steps in order to make an High DPI Awareness application for Windows 7. I'm not using ScaleBy & ScaleControls because those have a lot of bugs for this purpose.

STEP 1 - Declare High DPI Awareness

To do this we need a manifest file that includes the declaration, with the newest Lazarus subversion 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

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;

{$mode objfpc}{$H+}

interface

uses

 Graphics, Controls;
 

procedure ScaleDPI(Control: TControl; FromDPI: Integer);

implementation

procedure ScaleDPI(Control: TControl; FromDPI: Integer); var

 n: Integer;
 WinControl: TWinControl;

begin

 with Control do begin
   Left:=ScaleX(Left,FromDPI);
   Top:=ScaleY(Top,FromDPI);
   Width:=ScaleX(Width,FromDPI);
   Height:=ScaleY(Height,FromDPI);
   Font.Size := ScaleY(Font.Size,FromDPI);   
 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>

Copy the "uscaledpi.pas" file to the main folder of your project:

 MyProject\uscaledpi.pas
 

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>

OnCreate event of each form call the procedure in this way:

<delphi>procedure TForm1.FormCreate(Sender: TObject); begin

 if Screen.PixelsPerInch <> 96 then begin
   ScaleDPI(Self,96); // 96 is the DPI you designed the Form1  
 end;

end;</delphi>

Conclusion

Making your application aware of DPI setting and themes includes two steps :

  • 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

External Links