Ich habe eine Formularanwendung in C #. Wenn ich die DPI des Monitors ändere, bewegen sich alle Bedienelemente. Ich habe den Code verwendet this.AutoScaleMode = AutoScaleMode.Dpi
, aber das Problem wurde dadurch nicht vermieden.
Hat jemand eine Idee?
Antworten:
BEARBEITEN: Ab .NET 4.7 hat Windows Forms die Unterstützung für High DPI verbessert. Weitere Informationen finden Sie auf docs.microsoft.com. Es funktioniert jedoch nur für Win 10 Creators Update und höher, sodass es je nach Benutzerbasis möglicherweise noch nicht möglich ist, dies zu verwenden.
Schwierig, aber nicht unmöglich. Ihre beste Option ist natürlich, zu WPF zu wechseln, aber das ist möglicherweise nicht machbar.
Ich habe viel Zeit mit diesem Problem verbracht. Hier sind einige Regeln / Richtlinien, damit es ohne FlowLayoutPanel oder TableLayoutPanel ordnungsgemäß funktioniert:
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); // for design in 96 DPI
Ich garantiere, dass Sie in Ordnung sind, wenn Sie diese Richtlinien befolgen, auch wenn Sie Steuerelemente mit bestimmten Ankern platziert haben und kein Flowpanel verwenden. Wir haben eine auf diese Weise erstellte App auf Hunderten von Computern mit unterschiedlichen DPI-Einstellungen bereitgestellt und haben keine Beschwerden mehr. Alle Formulare / Container / Raster / Schaltflächen / Textfelder usw. sind korrekt skaliert, ebenso wie die Schriftart. Bilder funktionieren auch, aber bei hohen DPI-Werten neigen sie dazu, ein wenig pixelig zu werden.
BEARBEITEN: Dieser Link enthält viele gute Informationen, insbesondere wenn Sie AutoScaleMode.DPI verwenden: Link zu verwandten Fragen zum Stapelüberlauf
quelle
Hinweis: Dadurch werden die Steuerelemente nicht verschoben, wenn sich die Auflösung ändert. Dadurch wird nur verschwommener Text behoben !!.
So beheben Sie verschwommene Windows Forms in Einstellungen mit hoher Auflösung:
Gehen Sie nun zu Program.cs (oder der Datei, in der sich Ihre Main-Methode befindet) und ändern Sie sie wie folgt:
namespace myApplication { static class Program { [STAThread] static void Main() { // ***this line is added*** if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } // ***also dllimport of that function*** [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern bool SetProcessDPIAware(); } }
Speichern und kompilieren. Jetzt sollte Ihre Form wieder knusprig aussehen.
Quelle: http://crsouza.com/2015/04/13/how-to-fix-blurry-windows-forms-windows-in-high-dpi-settings/
quelle
Ich habe endlich eine Lösung für das Problem der Bildschirmorientierung und der DPI-Handhabung gefunden.
Microsoft hat bereits ein Dokument zur Erläuterung bereitgestellt, das jedoch einen kleinen Fehler aufweist, der die DPI-Verarbeitung vollständig beeinträchtigt. Befolgen Sie einfach die im folgenden Dokument unter "Erstellen eines separaten Layoutcodes für jede Ausrichtung" angegebene Lösung. Http://msdn.microsoft.com/en-us/library/ms838174.aspx
Dann WICHTIGER Teil! Fügen Sie im Code für die Methoden Landscape () und Portrait () ganz am Ende jeweils die folgenden Zeilen hinzu:
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
Der Code für diese beiden Methoden wäre also wie folgt:
protected void Portrait() { this.SuspendLayout(); this.crawlTime.Location = new System.Drawing.Point(88, 216); this.crawlTime.Size = new System.Drawing.Size(136, 16); this.crawlTimeLabel.Location = new System.Drawing.Point(10, 216); this.crawlTimeLabel.Size = new System.Drawing.Size(64, 16); this.crawlStartTime.Location = new System.Drawing.Point(88, 200); this.crawlStartTime.Size = new System.Drawing.Size(136, 16); this.crawlStartedLabel.Location = new System.Drawing.Point(10, 200); this.crawlStartedLabel.Size = new System.Drawing.Size(64, 16); this.light1.Location = new System.Drawing.Point(208, 66); this.light1.Size = new System.Drawing.Size(16, 16); this.light0.Location = new System.Drawing.Point(192, 66); this.light0.Size = new System.Drawing.Size(16, 16); this.linkCount.Location = new System.Drawing.Point(88, 182); this.linkCount.Size = new System.Drawing.Size(136, 16); this.linkCountLabel.Location = new System.Drawing.Point(10, 182); this.linkCountLabel.Size = new System.Drawing.Size(64, 16); this.currentPageBox.Location = new System.Drawing.Point(10, 84); this.currentPageBox.Size = new System.Drawing.Size(214, 90); this.currentPageLabel.Location = new System.Drawing.Point(10, 68); this.currentPageLabel.Size = new System.Drawing.Size(100, 16); this.addressLabel.Location = new System.Drawing.Point(10, 4); this.addressLabel.Size = new System.Drawing.Size(214, 16); this.noProxyCheck.Location = new System.Drawing.Point(10, 48); this.noProxyCheck.Size = new System.Drawing.Size(214, 20); this.startButton.Location = new System.Drawing.Point(8, 240); this.startButton.Size = new System.Drawing.Size(216, 20); this.addressBox.Location = new System.Drawing.Point(10, 24); this.addressBox.Size = new System.Drawing.Size(214, 22); //note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH! this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; //IMPORTANT this.ResumeLayout(false); } protected void Landscape() { this.SuspendLayout(); this.crawlTime.Location = new System.Drawing.Point(216, 136); this.crawlTime.Size = new System.Drawing.Size(96, 16); this.crawlTimeLabel.Location = new System.Drawing.Point(160, 136); this.crawlTimeLabel.Size = new System.Drawing.Size(48, 16); this.crawlStartTime.Location = new System.Drawing.Point(64, 120); this.crawlStartTime.Size = new System.Drawing.Size(248, 16); this.crawlStartedLabel.Location = new System.Drawing.Point(8, 120); this.crawlStartedLabel.Size = new System.Drawing.Size(48, 16); this.light1.Location = new System.Drawing.Point(296, 48); this.light1.Size = new System.Drawing.Size(16, 16); this.light0.Location = new System.Drawing.Point(280, 48); this.light0.Size = new System.Drawing.Size(16, 16); this.linkCount.Location = new System.Drawing.Point(80, 136); this.linkCount.Size = new System.Drawing.Size(72, 16); this.linkCountLabel.Location = new System.Drawing.Point(8, 136); this.linkCountLabel.Size = new System.Drawing.Size(64, 16); this.currentPageBox.Location = new System.Drawing.Point(10, 64); this.currentPageBox.Size = new System.Drawing.Size(302, 48); this.currentPageLabel.Location = new System.Drawing.Point(10, 48); this.currentPageLabel.Size = new System.Drawing.Size(100, 16); this.addressLabel.Location = new System.Drawing.Point(10, 4); this.addressLabel.Size = new System.Drawing.Size(50, 16); this.noProxyCheck.Location = new System.Drawing.Point(168, 16); this.noProxyCheck.Size = new System.Drawing.Size(152, 24); this.startButton.Location = new System.Drawing.Point(8, 160); this.startButton.Size = new System.Drawing.Size(304, 20); this.addressBox.Location = new System.Drawing.Point(10, 20); this.addressBox.Size = new System.Drawing.Size(150, 22); //note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH! this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; //IMPORTANT this.ResumeLayout(false); }
Funktioniert wie Charme für mich.
quelle
Creating Separate Layout Code for Each Orientation
Teil ist für die ursprüngliche Frage, eine Winform-Anwendung, irrelevant.Es sieht so aus, als ob dies ein Problem mit Windows ist. Das Herausnehmen dieser beiden Zeilen reparierte alles.
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
Hier habe ich die Lösung:
quelle
Es ist wirklich schwierig, DPI-fähige Anwendungen in Windows Forms zu entwerfen. Sie müssten Layout-Container verwenden, deren Größe sich ändert, wenn die DPI geändert wird (z. B. TableLayoutPanel oder FlowLayoutPanel). Alle Steuerelemente müssen ebenfalls in der Größe geändert werden. Die Konfiguration dieser Container kann eine Herausforderung sein.
Für einfache Anwendungen kann dies innerhalb eines angemessenen Zeitraums durchgeführt werden, für große Anwendungen ist es jedoch sehr viel Arbeit.
quelle
Aus Erfahrung:
AutoScaleMode
Eigenschaft fürNone
alle Formulare und Benutzersteuerelemente in Ihrer App immer aufquelle
Die ScaleByDPI-Funktion empfängt einen Control-Parameter, der normalerweise ein Formular ist, und durchläuft dann rekursiv alle Untersteuerelemente (if (control.HasChildren == true)) Betriebssystem konfigurierte DPI. Sie können versuchen, es auch für Bilder, Symbole und Grafiken zu implementieren.
Besondere Hinweise für die ScaleByDPI-Funktion:
ein. Für alle Steuerelemente mit Standardschriftgrößen müssen Sie ihre Schriftgröße auf 8,25 festlegen.
b. Sie können die Werte für devicePixelRatioX und devicePixelRatioY über (control.CreateGraphics (). DpiX / 96) und (control.CreateGraphics (). DpiY / 96) abrufen.
c. Sie benötigen die Skalierung Control.Size & Control.Location nach Algorithmus, der auf control.Dock & control.Anchor-Werten basiert. Beachten Sie, dass control.Dock möglicherweise 1 von 6 möglichen Werten und control.Anchor 1 von 16 möglichen Werten hat.
d. Für diesen Algorithmus müssen Werte für die nächsten Bool-Variablen festgelegt werden.
e. Wenn Ihr Projekt eine andere Steuerelementbibliothek als Microsoft-Steuerelemente verwendet, müssen diese Steuerelemente möglicherweise speziell behandelt werden.
Weitere Informationen zu den oben genannten (d.) Bool-Variablen:
* Manchmal muss eine Gruppe von Steuerelementen (möglicherweise eine Schaltfläche) nacheinander auf derselben vertikalen Linie platziert werden, und ihr Ankerwert umfasst Rechts, aber nicht Links, oder sie müssen nacheinander auf derselben horizontalen Linie platziert werden, und ihre Der Ankerwert umfasst "Unten", aber nicht "Oben". In diesem Fall müssen Sie die Positionswerte der Steuerelemente neu berechnen.
* Bei Steuerelementen, die Anchor oben und unten sowie \ oder links und rechts enthält, müssen Sie die Werte für Größe und Position der Steuerelemente neu faktorisieren.
Verwendung der ScaleByDPI-Funktion:
ein. Fügen Sie am Ende eines beliebigen Formularkonstruktors den nächsten Befehl hinzu: ScaleByDPI (this);
b. Auch beim dynamischen Hinzufügen eines Steuerelements zu einem Formularaufruf an ScaleByDPI ([ControlName]).
Wenn Sie die Größe oder Position eines Steuerelements nach dem Beenden des Konstruktors dynamisch festlegen, erstellen und verwenden Sie eine der nächsten Funktionen, um die skalierten Werte für Größe oder Position abzurufen: ScaleByDPI_X \ ScaleByDPI_Y \ ScaleByDPI_Size \ ScaleByDPI_Point
Fügen Sie das dpiAware-Element zum Assembly-Manifest Ihrer Anwendung hinzu, um Ihre Anwendung als DPI-fähig zu markieren.
Setzen Sie GraphicsUnit aller Control.Font auf System.Drawing.GraphicsUnit.Point
Setzen Sie in * .Designer.cs-Dateien aller Container den AutoScaleMode-Wert auf System.Windows.Forms.AutoScaleMode.None
In Steuerelementen wie ComboBox und TextBox hat das Ändern von Control.Size.Hieght keine Auswirkungen. In diesem Fall wird durch Ändern von Control.Font.Size die Höhe des Steuerelements festgelegt.
Wenn der Wert für Form StartPosition FormStartPosition.CenterScreen ist, müssen Sie die Position des Fensters neu berechnen.
quelle
Da ein Winform-Antragsformular möglicherweise Inhaltssteuerelemente UND Bilder enthält, ist es KEINE Lösung, dem System die Größe Ihres Fensters zu ändern. Wenn Sie jedoch ein Formular pro DPI-Auflösung mit ordnungsgemäß skalierten Bildern erstellen könnten, ist dies keine gute Idee. da mit zunehmender Bildschirmgröße die Schriftgröße abnimmt.
Wenn Sie eine andere DPI-Auflösung verwenden, zwingt das System Ihr Formular, die Größe, Position und Schriftart des Steuerelements neu zu definieren. ABER KEINE BILDER. Die Lösung besteht darin, die DPI des Formulars zur Laufzeit beim Laden so zu ändern, dass alles auf die ursprüngliche Größe und Position zurückkehrt.
Dies ist eine mögliche Lösung, die ich mit einer Kartenspielanwendung getestet habe, bei der ich etwa 80 Bildschaltflächen, TabControls usw. habe.
Fügen Sie in jedem form_Load-Ereignis dieses Code-Snippet hinzu:
Case Else '-- I use 125 AND NOT 120 because 120 is 25% more than 96 Me.Font = New Font(Me.Font.FontFamily, Me.Font.Size * 125 / dpi.DpiX) End Select
Außerdem ein schneller Trick zum Testen verschiedener Auflösungen auf demselben Computer ohne Neustart:
Ändern Sie über das Bedienfeld die Auflösung. Nicht neu starten! Schließen Sie stattdessen Ihre Sitzung und öffnen Sie eine neue mit demselben Benutzer.
Es gibt noch eine weitere Einschränkung: Wenn Sie die Größe und Position eines Steuerelements zur Laufzeit festlegen, sollten Sie denselben DPI-Faktor (z. B. 125 / Dpi.Dpix) auf die neuen Koordinaten anwenden. Sie sollten also eine globale DPIFactor-Variable aus dem Ereignis application.startup einrichten.
Zu guter Letzt:
Öffnen Sie Ihre Anwendung in Visual Studio NICHT mit einer anderen Auflösung als der ursprünglichen. Andernfalls werden ALLE IHRE STEUERUNGEN beim Öffnen jedes Formulars verschoben und in der Größe geändert, und es gibt keinen Weg zurück ...
Hoffe das hilft, viel Spaß beim Programmieren.
quelle