Difference between revisions of "High DPI/de"

From Lazarus wiki
Jump to navigationJump to search
m (page copied from english wiki page)
 
m (Fixed syntax highlighting; deleted category included in page template)
 
(18 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 
{{High DPI}}
 
{{High DPI}}
 +
<br>
 +
Zurück zu den [[Additional information/de|Zusätzlichen Informationen]].<br>
 +
<br>
 +
== Definition ==
 +
DPI (dots per inch = Punkte pro Zoll) ist das Verhältnis zwischen Größe in Pixeln und der tatsächlichen Anzeigegröße. Hier steht "Punkt" (dot) als Äquivalent für Pixel in der Druckterminologie. Anwendungen können entweder Pixelgrößen verwenden, oder die aktuelle Anzeigegröße berücksichtigen. In diesem zweiten Fall sind die Größen in "Punkten" angegeben.
  
== Definition ==
+
Unter Windows Vista und höher ist es möglich, das DPI-Verhältnis zu ändern, um Elemente größer darzustellen. High DPI ("Hochauflösung") bedeutet
Any custom DPI setting with more than 96 DPI (the default setting) [http://msdn.microsoft.com/en-us/library/ee318406(VS.85).aspx *].
+
jede benutzerdefinierte Textgröße (DPI) mit mehr als 96 DPI (Standard) [http://msdn.microsoft.com/en-us/library/ee318406(VS.85).aspx *].
 +
 
 +
High DPI awareness (= Berücksichtigung der Hochauflösung) bedeutet also, dass eine Anwendung diese DPI-Einstellungen beachtet.
 +
 
 +
== Pixel und Punkte ==
 +
 
 +
Zum Beispiel bedeutet 300 DPI, dass es 300 Pixel (oder dot) pro Inch gibt. Wenn aber dafür 72 Punkte pro Inch definiert sind, so bedeutet das:
 +
 
 +
300 Pixel ↔ 1 Inch
 +
 
 +
300/72 Pixel ↔ 1 Punkt
 +
 
 +
4.16 Pixel ↔ 1 Punkt
 +
 
 +
 
 +
Im Fall von 96 DPI gilt:
 +
 
 +
72 Pixel ↔ 1 Inch
 +
 
 +
1.33 Pixel ↔ 1 Punkt
 +
 
 +
 
 +
und bei 144 DPI:
 +
 
 +
144 Pixel ↔ 1 Inch
 +
 
 +
2 Pixel ↔ 1 Punkt
 +
 
 +
== Benutzerdefinierte Textgröße (High DPI) in Windows festlegen==
 +
Unter Windows 7 gehen Sie zu Systemsteuerung > Darstellung und Anpassung > Anzeige.
 +
 
 +
Wählen Sie: Kleiner 100% (Standard), Mittel 125% oder Größer 150%. Wenn Sie 100% (96 DPI) ausgewählt haben, ist das die Standardeinstellung von Windows für den DPI-Wert, aber nicht High DPI.
 +
 
 +
Bei 125% (120 DPI) ist die Option "DPI-Skalierung im Stil von Windows XP verwenden" aktiviert, Anwendungen werden unter diesen Einstellungen wie bei Windows XP skaliert.
 +
 
 +
Bei 150% (144 DPI) ist die Option "DPI-Skalierung im Stil von Windows XP verwenden" deaktiviert (die DPI Virtualisierung ist aktiviert). Anwendungen, die mit dieser Einstellung ablaufen, müssen selbst die Hochauflösung verwalten ("High DPI Awareness") ansonsten liefert die Skalierung des Systems ein verwischtes, unscharfes Bild.
 +
 
 +
Sie können den DPI-Wert auch mit dem Dialog "Benutzerdefinierte Textgröße (DPI) festlegen" einstellen und die DPI Virtualisierung aktivieren/ deaktivieren.
 +
 
 +
== Beispiel ==
 +
 
 +
Hier ist ein Formular mit undefinierter Fontgröße (Size ist auf 0 gesetzt; das ist der Vorgabewert). Entworfen bei 96 DPI (100%), sieht das so aus:
 +
 
 +
[[Image:Testdpi100.png]]
 +
 
 +
Jetzt mit 120 DPI (125%) wird es zu:
 +
 
 +
[[Image:Testdpi125.png]]
 +
 
 +
Wie Sie sehen wird die Schrift größer und abgeschnitten. Der Fenstertitel wird größer, aber der Clientbereich behält seine Abmessungen. Beachten Sie, dass diese Größenänderungen beim Einsatz verschiedener Windows-Themen oder eines anderen Betriebssystems auftreten können.
 +
 
 +
Um dies zu vermeiden setzen Sie die Schriftgröße (Size) auf einen Wert ungleich 0. Beachten Sie, dass Font.Size in Punkten angegeben wird und Font.Height in Pixel. Tatsächlich wird nur der Wert von Font.Height gespeichert und Font.Size ändert sich abhängig vom aktuellen DPI-Wert. Wenn wir also Font.Size angeben, wird die Schriftgröße auf eine bestimmte Größe in Pixeln festgelegt.
 +
 
 +
Ber einer fixierten Schriftgröße von 9 Punkt bei 96 DPI (100%), erhalten wir dies:
 +
 
 +
[[Image:Testdpi100fixedM12P9.png]]
 +
 
 +
Wenn jetzt das selbe Programm bei 120 DPI (125%) läuft, wird daraus:
 +
 
 +
[[Image:Testdpi125fixedM12P9.png]]
 +
 
 +
Das Ergebnis ist fast das selbe. Die Titelzeile ist größer, aber der Clientbereich und dessen Schriftgröße blieben gleich. Beachten Sie aber, dass sich die Punktgröße der Titelschriftart geändert hat.
 +
 
 +
Als Schlussfolgerung ist es möglich, Inkonsistenzen der Anzeige durch Festlegung der Schriftgrößen zu vermeiden. Aber wir berücksichtigen dabei nicht, dass die grafischen Elemente durch die aktuellen DPI des Bildschirms weniger Platz lassen. Bei Berücksichtigung der Hochauflösung ist es möglich, dass sich Anwendungen so verhalten, als wüßten sie die wirkliche Größe der Pixel.
 +
 
 +
== Beispiel (Windows) ==
 +
 
 +
[http://sourceforge.net/projects/cpicksniff2/ CPickSniff] ist eine Anwendung zum Abfragen der Farben am Bildschirm. Wir nehmen sie als Beispiel, wie sich High DPI unter Windows auswirkt.
 +
 
 +
=== Standard DPI ===
 +
 
 +
Das ist das Programm bei 96 DPI (100%). Es ist der Vorgabemodus, in dem keine Skalierung nötig ist.
 +
 
 +
[[Image:cpicksniff_defaultdpi.png]]
  
== Setting High DPI in Windows ==
+
=== Windows DPI Skalierung ===
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. The best way to get it is changing the settings and running applications under the different settings.
 
  
== High DPI in Lazarus ==
+
Dies ist das gleiche Programm bei 144 DPI (150%) ohne ein Manifest, also skaliert Windows es wie eine Bitmap. Das Ergebnis ist ein verwaschenes Bild.
  
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.
+
[[Image:cpicksniff_blured.png]]
  
=== STEP 1 - Declare High DPI Awareness ===
+
=== Mit Manifest ===
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 +)".
 
  
Else you can copy the below code and save to a text file "manifest.xml":
+
Ebenfalls bei 144 DPI (150%). Dieses Mal enthält die Anwendung ein Manifest, aber sie enthält keinen Code, um mit der Skalierung umzugehen. Die Elemente werden nicht skaliert, die Schrift schon (Windows macht das automatisch), also wird der Text abgeschnitten.
  
<xml><?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+
[[Image:cpicksniff_nohighdpi.png]]
  <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><description>Windows Shell</description>
 
  <dependency>
 
      <dependentAssembly>
 
          <assemblyIdentity
 
              type="win32"
 
              name="Microsoft.Windows.Common-Controls"
 
              version="6.0.0.0"
 
              processorArchitecture="*"
 
              publicKeyToken="6595b64144ccf1df"
 
              language="*"
 
          />
 
      </dependentAssembly>
 
  </dependency>
 
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
 
      <security>
 
          <requestedPrivileges>
 
              <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
 
          </requestedPrivileges>
 
      </security>
 
  </trustInfo>
 
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
 
      <windowsSettings>
 
          <dpiAware  xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
 
      </windowsSettings>
 
  </application>
 
</assembly></xml>
 
  
And save the below code to a text file "manifest.rc":
+
=== High DPI ===
  
  1 24 "manifest.xml"
+
Zuletzt mit Manifest und einem Skalierungshandler, die Anwendung ist in High DPI.
  
Then copy those files to the main folder of your project:
+
[[Image:cpicksniff_highdpi.png]]
  
  MyProject\manifest.xml
+
== Hochauflösender Text in Lazarus ==
  MyProject\manifest.rc
 
  
And include in your project:
+
Mit Lazarus erzeugen Sie eine Anwendung für hochauflösende Schriftgrößen unter Windows 7 mit den beiden folgenden Schritten.
  
<delphi>implementation
+
=== SCHRITT 1 - Deklarieren Sie High DPI Awareness ===
 
+
Dazu brauchen Sie eine Manifest-Datei die diese Deklaration enthält. Mit Lazarus 0.9.30 erreichen Sie dies mit Projekt > Projekteinstellungen > dann wählen Sie die Optionen "Themen mit Manifest-Datei einschalten (nur in Windows)" und "dpi-abhängige Anwendung (für Vista +)".
{$R *.lfm}
 
{$R manifest.rc} // This includes Windows Manifest to enable Themes and High DPI</delphi>
 
  
=== STEP 2 - Scale Forms and Controls ===
+
===SCHRITT 2 - Skalieren Sie die Formulare und Steuerelemente===
To do this we can call ScaleDPI procedure OnCreate event of each form in your project.
+
Dazu rufen Sie die folgende Prozedur 'ScaleDPI' im Ereignis 'OnCreate' eines jeden Formulars aus Ihrem Projekt auf.
  
First copy the below code and save to a text file "uscaledpi.pas":
+
Kopieren Sie zuerst den nachfolgenden Code und speichern Sie ihn in einer Textdatei namens "uscaledpi.pas":
  
<delphi>unit uscaledpi;
+
<syntaxhighlight lang=pascal>unit uscaledpi;
 
    
 
    
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 72: Line 119:
 
    
 
    
 
uses
 
uses
   Graphics, Controls;
+
   Forms, Graphics, Controls;
 
+
 +
procedure HighDPI(FromDPI: Integer);
 
procedure ScaleDPI(Control: TControl; FromDPI: Integer);
 
procedure ScaleDPI(Control: TControl; FromDPI: Integer);
 
+
 
implementation
 
implementation
    
+
 +
procedure HighDPI(FromDPI: Integer);
 +
var
 +
   i: Integer;
 +
begin
 +
  for i:=0 to Screen.FormCount-1 do
 +
    ScaleDPI(Screen.Forms[i],FromDPI);
 +
end;
 +
 
procedure ScaleDPI(Control: TControl; FromDPI: Integer);
 
procedure ScaleDPI(Control: TControl; FromDPI: Integer);
 
var
 
var
Line 83: Line 139:
 
   WinControl: TWinControl;
 
   WinControl: TWinControl;
 
begin
 
begin
 +
  if Screen.PixelsPerInch = FromDPI then exit;
 +
 
   with Control do begin
 
   with Control do begin
 
     Left:=ScaleX(Left,FromDPI);
 
     Left:=ScaleX(Left,FromDPI);
Line 88: Line 146:
 
     Width:=ScaleX(Width,FromDPI);
 
     Width:=ScaleX(Width,FromDPI);
 
     Height:=ScaleY(Height,FromDPI);
 
     Height:=ScaleY(Height,FromDPI);
 +
    Font.Height := ScaleY(Font.GetTextHeight('Hg'),FromDPI);
 
   end;
 
   end;
 +
 
   if Control is TWinControl then begin
 
   if Control is TWinControl then begin
 
     WinControl:=TWinControl(Control);
 
     WinControl:=TWinControl(Control);
Line 100: Line 160:
 
   end;
 
   end;
 
end;
 
end;
 
+
end.</delphi>
+
end.</syntaxhighlight>
  
Copy the "uscaledpi.pas" file to the main folder of your project:
+
Kopieren Sie diese Datei "uscaledpi.pas" in den Hauptordner Ihres Projekts:
  
 
   MyProject\uscaledpi.pas
 
   MyProject\uscaledpi.pas
 
    
 
    
In the "uses" section of your project you need to add "uScaleDPI":
+
Fügen Sie im Abschnitt "uses" von Ihrem Projekt den Ausdruck "uScaleDPI" hinzu:
  
<delphi>unit form1;
+
<syntaxhighlight lang=pascal>unit form1;
 
    
 
    
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 116: Line 176:
 
    
 
    
 
uses
 
uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs
+
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
   uScaleDPI; // This includes ScaleDPI procedure </delphi>
+
   uScaleDPI; // Dies enthält die Prozedur 'ScaleDPI'</syntaxhighlight>
 +
 
 +
Das OnCreate-Ereignis jedes Formulars ruft die Prozedur so auf:
 +
 
 +
<syntaxhighlight lang=pascal>procedure TForm1.FormCreate(Sender: TObject);
 +
begin
 +
  ScaleDPI(Self,96); // 96 ist der DPI-Wert beim Entwurf des Formulars 
 +
end;</syntaxhighlight>
 +
 
 +
=== Skalieren Sie alle Formulare ===
 +
 
 +
Sie können den Schritt 2 abändern, um alle Formulare zu skalieren.
 +
 
 +
Dazu öffnen Sie den Quelltext Ihres Projektes (typischerweise die Datei ''Project1.lpr'') und fügen 'uScaleDPI' im Abschnitt 'uses' hinzu.
 +
 
 +
Dann rufen Sie die Prozedur ''HighDPI'' nach dem Code der die Formulare initialisiert auf:
 +
 
 +
<syntaxhighlight lang=pascal>begin
 +
  RequireDerivedFormResource := True;
 +
  Application.Initialize;
 +
  Application.CreateForm(TForm1, Form1);
 +
  Application.CreateForm(TForm2, Form2);
 +
  Application.CreateForm(TForm3, Form3);
 +
  HighDPI(96); // 96 ist der DPI-Wert beim Entwurf der Formulare Form1, Form2 & Form3 
 +
  Application.Run;
 +
end.</syntaxhighlight>
 +
 
 +
Das Ergebnis sieht so aus:
 +
 
 +
<syntaxhighlight lang=pascal>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.</syntaxhighlight>
 +
 
 +
=== Fortgeschrittenes ===
 +
 
 +
Einige Steuerelemente haben mehr Eigenschaften oder abweichende Eigenschaftsnamen wie TToolBar-Buttons (ButtonHeight / ButtonWidth anstelle von Width / Height). Ebenso kann sich das Verhalten unter verschiedenen Betriebssystemen ändern, wenn Sie festgelegte Schriftgrößen verwenden.
 +
 
 +
Sie können die Prozedur 'ScaleDPI' anpassen, sodass der Code alle Steuerelemente in der von Ihnen gewünschten Weise skaliert.
 +
 
 +
Dies ist die in [[LazPaint]] verwendete Unit ''uscaledpi''. Sie ist beim Skalieren von ToolBars und ToolBox hilfreich. LazPaint verwendet auch fixe Schriftgrößen für eine einheitliche Darstellung unter verschiedenen Betriebssystemen.
 +
 
 +
<syntaxhighlight lang=pascal>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
  
OnCreate event of each form call the procedure in this way:
+
uses BGRABitmap, BGRABitmapTypes;
  
<delphi>procedure TForm1.FormCreate(Sender: TObject);
+
procedure HighDPI(FromDPI: Integer);
 +
var
 +
  i: Integer;
 
begin
 
begin
   if Screen.PixelsPerInch <> 96 then begin
+
   for i:=0 to Screen.FormCount-1 do begin
     ScaleDPI(Self,96); // 96 is the DPI you designed the Form1 
+
     ScaleDPI(Screen.Forms[i],FromDPI);
 
   end;
 
   end;
end;</delphi>
+
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);
 +
    Font.Height := ScaleY(Font.GetTextHeight('Hg'),FromDPI);
 +
  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.    </syntaxhighlight>
 +
 
 +
== Abschließende Bemerkungen ==
 +
 
 +
Das Entwickeln von Anwendungen, die die DPI-Einstellungen und Themen berücksichtigen, umfasst zwei Schritte:
 +
* Legen Sie eine fixe Schriftgröße fest zum Zeitpunkt der Entwickung (Nützlich für cross-platform Anwendungen, aber unnötig wenn nur Windows als Zielsystem)
 +
* Skalieren Sie die Komponenten zur Laufzeit
 +
* Passen Sie den ScaleDPI-Code an Ihre Bedürfnisse an
 +
 
 +
'''Anmerkung:'''
 +
 
 +
Siehe die Diskussionsseite für weitere Informationen: [[Talk:High_DPI]].
 +
 
 +
Wir verwenden nicht ScaleBy & ScaleControls:
 +
 
 +
<syntaxhighlight lang=pascal>Self.ScaleBy(Screen.PixelsPerInch,96);</syntaxhighlight>
 +
 
 +
Dies skaliert die Schrift, ist aber unter Windows überflüssig, weil das Betriebssystem die Schrift selbst ändert. Könnte nützlich sein, wenn Sie eine fixierte Schriftgröße verwenden.
 +
 
 +
<syntaxhighlight lang=pascal>Self.ScaleControls(Screen.PixelsPerInch,96);</syntaxhighlight>
 +
 
 +
Dies skaliert nicht die Breite / Höhe des Formulars. Könnte nützlich sein, wenn Sie diese selbst skalieren.
  
== External Links ==
+
== Externe 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.

Latest revision as of 08:18, 17 February 2020

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

Zurück zu den Zusätzlichen Informationen.

Definition

DPI (dots per inch = Punkte pro Zoll) ist das Verhältnis zwischen Größe in Pixeln und der tatsächlichen Anzeigegröße. Hier steht "Punkt" (dot) als Äquivalent für Pixel in der Druckterminologie. Anwendungen können entweder Pixelgrößen verwenden, oder die aktuelle Anzeigegröße berücksichtigen. In diesem zweiten Fall sind die Größen in "Punkten" angegeben.

Unter Windows Vista und höher ist es möglich, das DPI-Verhältnis zu ändern, um Elemente größer darzustellen. High DPI ("Hochauflösung") bedeutet jede benutzerdefinierte Textgröße (DPI) mit mehr als 96 DPI (Standard) *.

High DPI awareness (= Berücksichtigung der Hochauflösung) bedeutet also, dass eine Anwendung diese DPI-Einstellungen beachtet.

Pixel und Punkte

Zum Beispiel bedeutet 300 DPI, dass es 300 Pixel (oder dot) pro Inch gibt. Wenn aber dafür 72 Punkte pro Inch definiert sind, so bedeutet das:

300 Pixel ↔ 1 Inch

300/72 Pixel ↔ 1 Punkt

4.16 Pixel ↔ 1 Punkt


Im Fall von 96 DPI gilt:

72 Pixel ↔ 1 Inch

1.33 Pixel ↔ 1 Punkt


und bei 144 DPI:

144 Pixel ↔ 1 Inch

2 Pixel ↔ 1 Punkt

Benutzerdefinierte Textgröße (High DPI) in Windows festlegen

Unter Windows 7 gehen Sie zu Systemsteuerung > Darstellung und Anpassung > Anzeige.

Wählen Sie: Kleiner 100% (Standard), Mittel 125% oder Größer 150%. Wenn Sie 100% (96 DPI) ausgewählt haben, ist das die Standardeinstellung von Windows für den DPI-Wert, aber nicht High DPI.

Bei 125% (120 DPI) ist die Option "DPI-Skalierung im Stil von Windows XP verwenden" aktiviert, Anwendungen werden unter diesen Einstellungen wie bei Windows XP skaliert.

Bei 150% (144 DPI) ist die Option "DPI-Skalierung im Stil von Windows XP verwenden" deaktiviert (die DPI Virtualisierung ist aktiviert). Anwendungen, die mit dieser Einstellung ablaufen, müssen selbst die Hochauflösung verwalten ("High DPI Awareness") ansonsten liefert die Skalierung des Systems ein verwischtes, unscharfes Bild.

Sie können den DPI-Wert auch mit dem Dialog "Benutzerdefinierte Textgröße (DPI) festlegen" einstellen und die DPI Virtualisierung aktivieren/ deaktivieren.

Beispiel

Hier ist ein Formular mit undefinierter Fontgröße (Size ist auf 0 gesetzt; das ist der Vorgabewert). Entworfen bei 96 DPI (100%), sieht das so aus:

Testdpi100.png

Jetzt mit 120 DPI (125%) wird es zu:

Testdpi125.png

Wie Sie sehen wird die Schrift größer und abgeschnitten. Der Fenstertitel wird größer, aber der Clientbereich behält seine Abmessungen. Beachten Sie, dass diese Größenänderungen beim Einsatz verschiedener Windows-Themen oder eines anderen Betriebssystems auftreten können.

Um dies zu vermeiden setzen Sie die Schriftgröße (Size) auf einen Wert ungleich 0. Beachten Sie, dass Font.Size in Punkten angegeben wird und Font.Height in Pixel. Tatsächlich wird nur der Wert von Font.Height gespeichert und Font.Size ändert sich abhängig vom aktuellen DPI-Wert. Wenn wir also Font.Size angeben, wird die Schriftgröße auf eine bestimmte Größe in Pixeln festgelegt.

Ber einer fixierten Schriftgröße von 9 Punkt bei 96 DPI (100%), erhalten wir dies:

Testdpi100fixedM12P9.png

Wenn jetzt das selbe Programm bei 120 DPI (125%) läuft, wird daraus:

Testdpi125fixedM12P9.png

Das Ergebnis ist fast das selbe. Die Titelzeile ist größer, aber der Clientbereich und dessen Schriftgröße blieben gleich. Beachten Sie aber, dass sich die Punktgröße der Titelschriftart geändert hat.

Als Schlussfolgerung ist es möglich, Inkonsistenzen der Anzeige durch Festlegung der Schriftgrößen zu vermeiden. Aber wir berücksichtigen dabei nicht, dass die grafischen Elemente durch die aktuellen DPI des Bildschirms weniger Platz lassen. Bei Berücksichtigung der Hochauflösung ist es möglich, dass sich Anwendungen so verhalten, als wüßten sie die wirkliche Größe der Pixel.

Beispiel (Windows)

CPickSniff ist eine Anwendung zum Abfragen der Farben am Bildschirm. Wir nehmen sie als Beispiel, wie sich High DPI unter Windows auswirkt.

Standard DPI

Das ist das Programm bei 96 DPI (100%). Es ist der Vorgabemodus, in dem keine Skalierung nötig ist.

cpicksniff defaultdpi.png

Windows DPI Skalierung

Dies ist das gleiche Programm bei 144 DPI (150%) ohne ein Manifest, also skaliert Windows es wie eine Bitmap. Das Ergebnis ist ein verwaschenes Bild.

cpicksniff blured.png

Mit Manifest

Ebenfalls bei 144 DPI (150%). Dieses Mal enthält die Anwendung ein Manifest, aber sie enthält keinen Code, um mit der Skalierung umzugehen. Die Elemente werden nicht skaliert, die Schrift schon (Windows macht das automatisch), also wird der Text abgeschnitten.

cpicksniff nohighdpi.png

High DPI

Zuletzt mit Manifest und einem Skalierungshandler, die Anwendung ist in High DPI.

cpicksniff highdpi.png

Hochauflösender Text in Lazarus

Mit Lazarus erzeugen Sie eine Anwendung für hochauflösende Schriftgrößen unter Windows 7 mit den beiden folgenden Schritten.

SCHRITT 1 - Deklarieren Sie High DPI Awareness

Dazu brauchen Sie eine Manifest-Datei die diese Deklaration enthält. Mit Lazarus 0.9.30 erreichen Sie dies mit Projekt > Projekteinstellungen > dann wählen Sie die Optionen "Themen mit Manifest-Datei einschalten (nur in Windows)" und "dpi-abhängige Anwendung (für Vista +)".

SCHRITT 2 - Skalieren Sie die Formulare und Steuerelemente

Dazu rufen Sie die folgende Prozedur 'ScaleDPI' im Ereignis 'OnCreate' eines jeden Formulars aus Ihrem Projekt auf.

Kopieren Sie zuerst den nachfolgenden Code und speichern Sie ihn in einer Textdatei namens "uscaledpi.pas":

unit uscaledpi;
  
{$mode objfpc}{$H+}
  
interface
  
uses
  Forms, Graphics, Controls;
 
procedure HighDPI(FromDPI: Integer);
procedure ScaleDPI(Control: TControl; FromDPI: Integer);
 
implementation
 
procedure HighDPI(FromDPI: Integer);
var
  i: Integer;
begin
  for i:=0 to Screen.FormCount-1 do
    ScaleDPI(Screen.Forms[i],FromDPI);
end;
 
procedure ScaleDPI(Control: TControl; FromDPI: Integer);
var
  n: Integer;
  WinControl: TWinControl;
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);
    Font.Height := ScaleY(Font.GetTextHeight('Hg'),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.

Kopieren Sie diese Datei "uscaledpi.pas" in den Hauptordner Ihres Projekts:

 MyProject\uscaledpi.pas
 

Fügen Sie im Abschnitt "uses" von Ihrem Projekt den Ausdruck "uScaleDPI" hinzu:

unit form1;
  
{$mode objfpc}{$H+}
  
interface
  
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
  uScaleDPI; // Dies enthält die Prozedur 'ScaleDPI'

Das OnCreate-Ereignis jedes Formulars ruft die Prozedur so auf:

procedure TForm1.FormCreate(Sender: TObject);
begin
  ScaleDPI(Self,96); // 96 ist der DPI-Wert beim Entwurf des Formulars  
end;

Skalieren Sie alle Formulare

Sie können den Schritt 2 abändern, um alle Formulare zu skalieren.

Dazu öffnen Sie den Quelltext Ihres Projektes (typischerweise die Datei Project1.lpr) und fügen 'uScaleDPI' im Abschnitt 'uses' hinzu.

Dann rufen Sie die Prozedur HighDPI nach dem Code der die Formulare initialisiert auf:

begin
  RequireDerivedFormResource := True;
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TForm2, Form2);
  Application.CreateForm(TForm3, Form3);
  HighDPI(96); // 96 ist der DPI-Wert beim Entwurf der Formulare Form1, Form2 & Form3  
  Application.Run;
end.

Das Ergebnis sieht so aus:

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.

Fortgeschrittenes

Einige Steuerelemente haben mehr Eigenschaften oder abweichende Eigenschaftsnamen wie TToolBar-Buttons (ButtonHeight / ButtonWidth anstelle von Width / Height). Ebenso kann sich das Verhalten unter verschiedenen Betriebssystemen ändern, wenn Sie festgelegte Schriftgrößen verwenden.

Sie können die Prozedur 'ScaleDPI' anpassen, sodass der Code alle Steuerelemente in der von Ihnen gewünschten Weise skaliert.

Dies ist die in LazPaint verwendete Unit uscaledpi. Sie ist beim Skalieren von ToolBars und ToolBox hilfreich. LazPaint verwendet auch fixe Schriftgrößen für eine einheitliche Darstellung unter verschiedenen Betriebssystemen.

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);
    Font.Height := ScaleY(Font.GetTextHeight('Hg'),FromDPI);
  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.

Abschließende Bemerkungen

Das Entwickeln von Anwendungen, die die DPI-Einstellungen und Themen berücksichtigen, umfasst zwei Schritte:

  • Legen Sie eine fixe Schriftgröße fest zum Zeitpunkt der Entwickung (Nützlich für cross-platform Anwendungen, aber unnötig wenn nur Windows als Zielsystem)
  • Skalieren Sie die Komponenten zur Laufzeit
  • Passen Sie den ScaleDPI-Code an Ihre Bedürfnisse an

Anmerkung:

Siehe die Diskussionsseite für weitere Informationen: Talk:High_DPI.

Wir verwenden nicht ScaleBy & ScaleControls:

Self.ScaleBy(Screen.PixelsPerInch,96);

Dies skaliert die Schrift, ist aber unter Windows überflüssig, weil das Betriebssystem die Schrift selbst ändert. Könnte nützlich sein, wenn Sie eine fixierte Schriftgröße verwenden.

Self.ScaleControls(Screen.PixelsPerInch,96);

Dies skaliert nicht die Breite / Höhe des Formulars. Könnte nützlich sein, wenn Sie diese selbst skalieren.

Externe Links