High DPI/de

From Lazarus wiki
Revision as of 16:35, 24 June 2011 by Billyraybones (talk | contribs) (updated)
Jump to navigationJump to search

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

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. Es sind aber auch 72 Punkte pro Inch, also gilt:

300 Pixel ↔ 1 Inch

300/72 Pixel ↔ 1 Punkt

4.16 Pixel ↔ 1 Punkt


Jetzt bei 96 DPI:

72 Pixel ↔ 1 Inch

1.33 Pixel ↔ 1 Punkt


Jetzt 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":

<delphi>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 begin
   ScaleDPI(Screen.Forms[i],FromDPI);
 end;

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.</delphi>

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:

<delphi>unit form1;

{$mode objfpc}{$H+}

interface

uses

 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
 uScaleDPI; // Dies enthält die Prozedur 'ScaleDPI'</delphi>

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

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

 ScaleDPI(Self,96); // 96 ist der DPI-Wert beim Entwurf des Formulars  

end;</delphi>

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:

<delphi>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.</delphi>

Das Ergebnis sieht so aus:

<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>

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.

<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);
   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. </delphi>

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:

<delphi>Self.ScaleBy(Screen.PixelsPerInch,96);</delphi>

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.

<delphi>Self.ScaleControls(Screen.PixelsPerInch,96);</delphi>

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

Externe Links