Hinweis: Bitte beachten Sie die anderen Antworten, da diese sehr wertvolle Techniken enthalten. Meine Antwort hier enthält nur Vorbehalte und Vorsichtsmaßnahmen gegen die Annahme, dass das DPI-Bewusstsein einfach ist.
Ich vermeide generell DPI-fähige Skalierung mit TForm.Scaled = True
. Das DPI-Bewusstsein ist für mich nur dann wichtig, wenn es für Kunden wichtig wird, die mich anrufen und bereit sind, dafür zu zahlen. Der technische Grund für diese Sichtweise ist, dass DPI-Bewusstsein oder nicht, Sie ein Fenster in eine Welt voller Verletzungen öffnen. Viele Standard- und VCL-Steuerelemente von Drittanbietern funktionieren in High DPI nicht gut. Die bemerkenswerte Ausnahme, dass die VCL-Teile, die Windows Common Controls umschließen, bei hohen DPI bemerkenswert gut funktionieren. Eine große Anzahl von benutzerdefinierten Delphi VCL-Steuerelementen von Drittanbietern funktioniert bei hohen DPI-Werten nicht oder überhaupt nicht. Wenn Sie TForm.Scaled aktivieren möchten, testen Sie es mit 96, 125 und 150 DPI für jedes einzelne Formular in Ihrem Projekt sowie für jeden einzelnen Drittanbieter und jede integrierte Steuerung, die Sie verwenden.
Delphi selbst ist in Delphi geschrieben. Für die meisten Formulare ist das High DPI Awareness-Flag aktiviert, obwohl die IDE-Autoren selbst in Delphi XE2 selbst noch entschieden haben, das High DPI Awareness-Manifest NICHT zu aktivieren. Beachten Sie, dass in Delphi XE4 und höher das HIGH DPI-Erkennungsflag aktiviert ist und die IDE gut aussieht.
Ich schlage vor, dass Sie TForm.Scaled = true (dies ist eine Standardeinstellung in Delphi. Wenn Sie es nicht geändert haben, haben die meisten Ihrer Formulare Scaled = true) mit den High DPI Aware-Flags (wie in Davids Antworten gezeigt) mit verwenden VCL-Anwendungen, die mit dem integrierten Delphi-Formular-Designer erstellt wurden.
Ich habe in der Vergangenheit versucht, eine minimale Stichprobe der Art von Bruch zu erstellen, die zu erwarten ist, wenn TForm.Scaled wahr ist und wenn die Delphi-Formskalierung einen Fehler aufweist. Diese Störungen werden nicht immer und nur durch einen anderen DPI-Wert als 96 ausgelöst. Ich konnte keine vollständige Liste anderer Dinge ermitteln, einschließlich Änderungen der Windows XP-Schriftgröße. Da die meisten dieser Störungen jedoch nur in meinen eigenen Anwendungen auftreten, habe ich mich in relativ komplexen Situationen entschlossen, Ihnen einige Beweise zu zeigen, die Sie selbst überprüfen können.
Delphi XE sieht folgendermaßen aus, wenn Sie die DPI-Skalierung in Windows 7 auf "Fonts @ 200%" einstellen und Delphi XE2 unter Windows 7 und 8 ebenfalls fehlerhaft ist. Diese Störungen scheinen jedoch ab Delphi XE4 behoben zu sein:
Dies sind meistens Standard-VCL-Steuerelemente, die sich bei hohen DPI-Werten schlecht verhalten. Beachten Sie, dass die meisten Dinge überhaupt nicht skaliert wurden. Daher haben die Delphi IDE-Entwickler beschlossen, die DPI-Erkennung zu ignorieren und die DPI-Virtualisierung zu deaktivieren. Eine so interessante Wahl.
Deaktivieren Sie die DPI-Virtualisierung nur, wenn Sie diese neue zusätzliche Schmerzquelle und schwierige Entscheidungen wünschen. Ich schlage vor, Sie lassen es in Ruhe. Beachten Sie, dass die allgemeinen Windows-Steuerelemente meistens einwandfrei funktionieren. Beachten Sie, dass das Delphi Data Explorer-Steuerelement ein C # WinForms-Wrapper um ein allgemeines Standard-Windows Tree-Steuerelement ist. Dies ist ein reiner Microsoft-Fehler, und zur Behebung dieses Problems muss Embarcadero möglicherweise ein reines natives .Net-Baumsteuerelement für den Datenexplorer neu schreiben oder einen Code für DPI-Überprüfungs- und -Eigenschaftseigenschaften schreiben, um die Elementhöhen im Steuerelement zu ändern. Nicht einmal Microsoft WinForms kann hohe DPI sauber, automatisch und ohne benutzerdefinierten Kludge-Code verarbeiten.
Update: Interessantes Faktoid: Während die Delphi-IDE nicht "virtualisiert" zu sein scheint, verwendet sie nicht den von David gezeigten Manifest-Inhalt, um eine "Nicht-DPI-Virtualisierung" zu erreichen. Möglicherweise wird zur Laufzeit eine API-Funktion verwendet.
Update 2: Als Antwort darauf, wie ich 100% / 125% DPI unterstützen würde, würde ich einen Zwei-Phasen-Plan erstellen. In Phase 1 wird mein Code für benutzerdefinierte Steuerelemente inventarisiert, die für hohe DPI repariert werden müssen, und anschließend ein Plan erstellt, um sie zu reparieren oder auslaufen zu lassen. Phase 2 besteht darin, einige Bereiche meines Codes, die als Formulare ohne Layoutverwaltung konzipiert sind, in Formulare umzuwandeln, die eine Art Layoutverwaltung verwenden, damit Änderungen der DPI oder der Schrifthöhe ohne Beschneiden funktionieren können. Ich vermute, dass diese "Inter-Control" -Layout-Arbeit in den meisten Anwendungen weitaus komplexer wäre als die "Intra-Control" -Arbeit.
Update: 2016 funktioniert das neueste Delphi 10.1 Berlin gut auf meiner 150-dpi-Workstation.
SetProcessDPIAware
.Ihre Einstellungen in der .dfm Datei wird korrekt skaliert, so lange
Scaled
istTrue
.Wenn Sie Dimensionen im Code festlegen, müssen Sie sie durch
Screen.PixelsPerInch
dividiert durch skalierenForm.PixelsPerInch
. VerwendenMulDiv
Sie dazu.Dies ist, was das Form Persistence Framework tut, wenn es
Scaled
istTrue
.Tatsächlich können Sie ein schlüssiges Argument dafür vorbringen, diese Funktion durch eine Version zu ersetzen, die einen Wert von 96 für den Nenner fest codiert. Auf diese Weise können Sie absolute Bemaßungswerte verwenden und müssen sich keine Gedanken über die Änderung der Bedeutung machen, wenn Sie die Schriftartenskalierung auf Ihrem Entwicklungscomputer ändern und die .dfm-Datei erneut speichern. Der Grund dafür ist, dass die
PixelsPerInch
in der .dfm-Datei gespeicherte Eigenschaft der Wert des Computers ist, auf dem die .dfm-Datei zuletzt gespeichert wurde.Wenn Sie das Thema fortsetzen, sollten Sie auch bedenken, dass wenn Ihr Projekt auf mehreren Computern mit unterschiedlichen DPI-Werten entwickelt wird, die Skalierung, die Delphi beim Speichern von .dfm-Dateien verwendet, dazu führt, dass Steuerelemente über eine Reihe von Änderungen wandern . Um dies zu vermeiden, haben wir an meinem Arbeitsplatz die strikte Richtlinie, dass Formulare immer nur mit 96 dpi (100% Skalierung) bearbeitet werden.
Tatsächlich
ScaleFromSmallFontsDimension
berücksichtigt meine Version von auch die Möglichkeit, dass sich die Formularschrift zur Laufzeit von der zur Entwurfszeit festgelegten unterscheidet. Auf XP-Computern verwenden die Formulare meiner Anwendung 8pt Tahoma. Unter Vista und höher wird 9pt Segoe UI verwendet. Dies bietet noch einen weiteren Freiheitsgrad. Die Skalierung muss dies berücksichtigen, da angenommen wird, dass die im Quellcode verwendeten absoluten Dimensionswerte relativ zur Basislinie von 8pt Tahoma bei 96 dpi sind.Wenn Sie Bilder oder Glyphen in Ihrer Benutzeroberfläche verwenden, müssen diese ebenfalls skaliert werden. Ein häufiges Beispiel sind die Glyphen, die in Symbolleisten und Menüs verwendet werden. Sie möchten diese Glyphen als Symbolressourcen bereitstellen, die mit Ihrer ausführbaren Datei verknüpft sind. Jedes Symbol sollte eine Reihe von Größen enthalten. Zur Laufzeit wählen Sie die am besten geeignete Größe aus und laden sie in eine Bildliste. Einige Details zu diesem Thema finden Sie hier: Wie lade ich Symbole aus einer Ressource, ohne unter Aliasing zu leiden?
Ein weiterer nützlicher Trick besteht darin, Dimensionen in relativen Einheiten relativ zu
TextWidth
oder zu definierenTextHeight
. Wenn Sie also möchten, dass etwas ungefähr 10 vertikale Linien groß ist, können Sie es verwenden10*Canvas.TextHeight('Ag')
. Dies ist eine sehr grobe und fertige Metrik, da sie keinen Zeilenabstand usw. zulässt. Oft müssen Sie jedoch nur sicherstellen, dass die GUI korrekt skaliertPixelsPerInch
.Sie sollten Ihre Anwendung auch als hoch DPI-fähig markieren . Der beste Weg, dies zu tun, ist über das Anwendungsmanifest. Da Sie mit den Build-Tools von Delphi das verwendete Manifest nicht anpassen können, müssen Sie Ihre eigene Manifest-Ressource verknüpfen.
Das Ressourcenskript sieht folgendermaßen aus:
wo
Manifest.txt
enthält das eigentliche Manifest. Sie würde auch den comctl32 v6 Abschnitt und Set enthalten müssenrequestedExecutionLevel
zuasInvoker
. Anschließend verknüpfen Sie diese kompilierte Ressource mit Ihrer App und stellen sicher, dass Delphi nicht versucht, dasselbe mit seinem Manifest zu tun. Im modernen Delphi erreichen Sie dies, indem Sie die Projektoption Runtime Themes auf None setzen.Das Manifest ist der richtige Weg, um Ihre App als hoch DPI-fähig zu deklarieren. Wenn Sie es nur schnell ausprobieren möchten, ohne Ihr Manifest zu beeinträchtigen, rufen Sie an
SetProcessDPIAware
. Tun Sie dies als erstes, wenn Ihre App ausgeführt wird. Am besten in einem der frühen Abschnitte zur Einheiteninitialisierung oder als erstes in Ihrer .dpr-Datei.Wenn Sie Ihre App nicht als hoch DPI-fähig deklarieren, wird sie von Vista und höher in einem Legacy-Modus für alle Schriftarten skaliert, die über 125% liegen. Das sieht ziemlich schrecklich aus. Versuche zu vermeiden, in diese Falle zu tappen.
Windows 8.1 pro Monitor DPI-Update
Ab Windows 8.1 gibt es jetzt Betriebssystemunterstützung für DPI-Einstellungen pro Monitor ( http://msdn.microsoft.com/en-ca/magazine/dn574798.aspx ). Dies ist ein großes Problem für moderne Geräte, an die möglicherweise unterschiedliche Displays mit sehr unterschiedlichen Funktionen angeschlossen sind. Möglicherweise haben Sie einen Laptop-Bildschirm mit sehr hoher DPI und einen externen Projektor mit niedriger DPI. Die Unterstützung eines solchen Szenarios erfordert noch mehr Arbeit als oben beschrieben.
quelle
Es ist auch wichtig zu beachten, dass die Einhaltung der DPI des Benutzers nur eine Teilmenge Ihres eigentlichen Jobs ist:
Seit Jahrzehnten löst Windows dieses Problem mit dem Gedanken, das Layout mithilfe von Dialogeinheiten anstelle von Pixeln durchzuführen . Eine "Dialogeinheit" ist so definiert, dass das durchschnittliche Zeichen der Schriftart ist
Delphi wird mit einer (fehlerhaften) Vorstellung von ausgeliefert
Scaled
, bei der ein Formular versucht, sich basierend auf dem automatisch anzupassenDies löst das Problem nicht, wenn der Benutzer eine andere Schriftart verwendet als die, mit der Sie das Formular entworfen haben, z.
6.21px x 13.00px
bei 96 dpi liegt).Benutzer, der mit Tahoma 8pt läuft (wobei das durchschnittliche Zeichen
5.94px x 13.00px
bei 96 dpi liegt)Wie bei jedem, der eine Anwendung für Windows 2000 oder Windows XP entwickelt.
oder
5.94px x 13.00px
bei 96 dpi liegt)6.67px x 15px
bei 96 dpi liegt)Als guter Entwickler werden Sie die Schriftarteneinstellungen Ihres Benutzers berücksichtigen. Dies bedeutet, dass Sie auch alle Steuerelemente in Ihrem Formular skalieren müssen, um sie an die neue Schriftgröße anzupassen:
Scaled
Ich werde das nicht für dich erledigen.Es wird schlimmer, wenn:
10.52px x 25px
Jetzt müssen Sie alles skalieren
Scaled
Ich werde das nicht für dich erledigen.Wenn Sie schlau sind, können Sie sehen, wie irrelevant es ist, DPI zu ehren:
Sie sollten nicht auf die DPI-Einstellung des Benutzers achten, sondern auf dessen Schriftgröße . Zwei Benutzer laufen
führen die gleiche Schriftart aus . DPI ist nur eine Sache, die die Schriftgröße beeinflusst. Die Vorlieben des Benutzers sind die anderen.
StandardizeFormFont
Clovis bemerkte, dass ich auf eine Funktion verweise
StandardizeFormFont
, die die Schriftart in einem Formular korrigiert und auf die neue Schriftgröße skaliert. Es ist keine Standardfunktion, sondern eine ganze Reihe von Funktionen, die die einfache Aufgabe erfüllen, die Borland nie erledigt hat.Windows hat 6 verschiedene Schriftarten; In Windows gibt es keine einzige "Schriftarteinstellung".
Wir wissen jedoch aus Erfahrung, dass unsere Formulare der Einstellung für die Symbolschriftart folgen sollten
Sobald wir die Schriftgröße wissen , werden wir die Form skalieren zu , so erhalten wir die aktuelle Schrifthöhe des Formulars ( in Pixeln ) und skalieren um diesen Faktor auf.
Wenn ich beispielsweise das Formular auf
-16
setze und das Formular sich derzeit in befindet-11
, müssen wir das gesamte Formular skalieren nach:Die Standardisierung erfolgt in zwei Phasen. Skalieren Sie das Formular zunächst nach dem Verhältnis der neuen zu den alten Schriftgrößen. Ändern Sie dann tatsächlich die Steuerelemente (rekursiv), um die neue Schriftart zu verwenden.
Hier ist die Aufgabe, ein Formular tatsächlich zu skalieren. Es umgeht Fehler in Borlands eigener
Form.ScaleBy
Methode. Zuerst müssen alle Anker im Formular deaktiviert, dann die Skalierung durchgeführt und dann die Anker wieder aktiviert werden:und dann müssen wir rekursiv tatsächlich verwenden die neue Schriftart:
Wenn die Anker rekursiv deaktiviert sind:
Und Anker werden rekursiv wieder aktiviert:
Mit der Arbeit, eine Steuerelementschrift tatsächlich zu ändern, bleibt Folgendes übrig:
Das ist viel mehr Code, als Sie gedacht haben. ich weiß. Das Traurige ist, dass es keinen Delphi-Entwickler auf der Welt gibt, außer mir, der seine Anwendungen tatsächlich korrekt macht.
quelle
Hier ist mein Geschenk. Eine Funktion, die Ihnen bei der horizontalen Positionierung von Elementen in Ihren GUI-Layouts helfen kann. Frei für alle.
quelle