Windows Form Skalierung / Anpassung

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 26 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Windows Form Skalierung / Anpassung

    Hallo,

    wie schon im Titel zu Lesen habe ich ein Problem mit der Skalierbarkeit meiner Anwendung.
    Ich habe ein kleines Programm in VS 2015 (Windows Forms) bei einer Auflösung von 1920x1080 erstellt.



    Mein Problem:
    Ich möchte diese Anwendung gerne auf meinem Notebook nutzen möchte (Dell XPS 13).
    Hier läuft eine Skalierung von 150% daher ist meine Anwendung viel zu Groß.

    Wie kann ich eine Automatische Skalierung bei Windows Forms Anwendungen implementieren?

    Habe natürlich bereits Gegoogelt aber keine wirkliche Lösung bzw. kein Beispiel gefunden!
    Es geht mir aber hier nicht darum das ich meine Form Größe ändern kann (FormBorderStyle=Sizable).

    Sonder das sich meine Anwendung auf einem Rechner mit niedriger o. höherer Auflösung automatisch Anpasst!

    Wenn das mit Windows Forms Anwendungen überhaupt möglich ist?

    Würde mich über eine Antwort freuen!

    LG Raffael
    Ist die Frage was in der Größe skalierbar sein soll. Bei Controls wie Buttons, Panels etc. skaliert man am einfachsten mit den Properties Anchor & Dock, die Größe relativ zum Fenster anpassen.
    Bei Beschriftungen etc. wird die Sache schon etwas schwieriger. Da musst du die Fenstergröße überwachen und manuell regulieren.
    Option strict = on

    If it's stupid and it works it ain't stupid.
    Danke für deine Antwort,

    grundsätzlichkeit wäre es mal schön wenn meine Anwendung/Controls sich Proportional zur Auflösung Skalieren würde.

    Das mit Anchor und Dock ist mir bekannt und wird in meine Anwendung auch eingesetzt.
    Das Problem ist soweit ich Anchor und Dock verstanden habe das sich meine Form bzw. die Controls darauf, sich nur bei einer Veränderung der Größe meiner Form verändern.

    Meine Anwendung soll sich aber nicht Größer oder Kleiner ziehen lassen (FormBorderStyle=None).

    Ich würde mich als Programmier Anfänger einstufen, vielleicht denke ich falsch aber Anchor und Dock ist hier ich nicht die Lösung oder?

    LG Raffael
    Ah dir geht es eigentlich nicht um eine Skalierung in Relation zur Größe, sondern zur Pixeldichte des Monitors. Als Win-Forms entworfen wurde gab es das Problem mit der hohen Pixeldichte noch nicht.
    Ergo sind entsprechende Tools nur rudimentär vorhanden.

    WPF (Windows Presentation Foundation) ist darauf ausgelegt mit unterschiedlichen Pixeldichten zu hantieren und es wird überall empfohlen auf WPF zu gehen, wenn man mit stark unterschiedlichen Auflösungen
    arbeiten will.

    Wenn du noch nicht sonderlich weit mit deiner Anwendung bist, währe es wahrscheinlich am einfachsten von WinForms auf WPF zu wechseln.
    Option strict = on

    If it's stupid and it works it ain't stupid.

    RevangeXX schrieb:

    Meine Anwendung soll sich aber nicht Größer oder Kleiner ziehen lassen (FormBorderStyle=None).
    Das ist natürlich problematisch.
    Wenn du damit auf einen zu kleinen Bildschirm kommst, ist dein Form natürlich zu groß, und Teile davon unerreichbar.

    Imo anzupassen ans Window-Zoom gibts da garnix. Natürlich müssen alle deine Elemente, und auch dein Form um 150% vergrößert werden, wenn der User 150% eingestellt hat - was denn sonst?
    Wie gesagt: Mach dein Formlayout flexibel, und machs nicht zu groß, dann ist alles fein.
    Kannste auch mit WindowState.Maximized anzeigen, dann füllt es immer genau den Bildschirm aus.
    kann man hierfür nicht eine Funktion schreiben, die beim Load die Auflösung ausliest und daraus prozentual die Controls etc. anpasst?
    Ich bin mir nicht sicher in wiefern das zu bewältigen ist, aber das Problem mit der Auflösung gibt es ja schon länger...

    Wenn alles mit Dock und Anchor erstellt wurde, muss man ja tatsächlich nur die Größe und ggf. Font-Size der Auflösung anpassen.
    Vielleicht lässt sich damit ja was brauchbares machen..
    Wenn das Leben wirklich nur aus Nullen und Einsen besteht, dann laufen sicherlich genügen Nullen frei herum. :D
    Signature-Move 8o
    kein Problem mit privaten Konversationen zu Thema XY :thumbup:
    Zur Anpassung der Anzeige eines zweiten Displays habe ich mal folgende Funktion erstellt:

    VB.NET-Quellcode

    1. Public Shared Sub ScaleToScreen(FormToResize As Form, ScreenNumber As Int32, Debug As Boolean)
    2. Dim m_screen As Screen
    3. If Screen.AllScreens.Length > ScreenNumber Then
    4. m_screen = Screen.AllScreens(ScreenNumber)
    5. Else
    6. m_screen = Screen.AllScreens(0)
    7. ScreenNumber = 0
    8. End If
    9. ' Set the StartPosition to Manual otherwise the system will assign an automatic start position
    10. FormToResize.StartPosition = FormStartPosition.Manual
    11. FormToResize.AutoScaleMode = AutoScaleMode.None
    12. '
    13. ' Set the form location so it appears at Location (0, 0) on the screen 1
    14. '
    15. FormToResize.Location = m_screen.Bounds.Location
    16. Dim NewX As Integer = m_screen.Bounds.Width
    17. Dim NewY As Integer = m_screen.Bounds.Height
    18. Dim FactorX = NewX / FormToResize.Width
    19. Dim FactorY = NewY / FormToResize.Height
    20. If Debug Then
    21. Exit Sub
    22. End If
    23. Dim NewLocation = New Point(CInt(FormToResize.Location.X / FactorX), CInt(FormToResize.Location.Y / FactorY))
    24. FormToResize.Location = NewLocation
    25. ScaleRecursive(FormToResize, FactorX, FactorY)
    26. End Sub
    27. Private Shared Sub ScaleRecursive(ParentControl As Control, FactorX As Double, FactorY As Double)
    28. Dim NewLocation = New Point(CInt(ParentControl.Location.X * FactorX), CInt(ParentControl.Location.Y * FactorY))
    29. ParentControl.Location = NewLocation
    30. Dim NewFontHeight As Single = CSng(ParentControl.Font.SizeInPoints * FactorY)
    31. ParentControl.Font = New Font(ParentControl.Font.Name, NewFontHeight, ParentControl.Font.Style)
    32. Dim NewSize = New Size(CInt(ParentControl.Width * FactorX), CInt(ParentControl.Height * FactorY))
    33. ParentControl.Size = NewSize
    34. For Each ChildControl As Control In ParentControl.Controls
    35. ScaleRecursive(ChildControl, FactorX, FactorY)
    36. Next
    37. End Sub

    Für die Skalierung der Fonts habe ich Die Referenz-Höhe verwendet, weil das für das damalige Projekt genügte. Wenn auch die Breite von belang ist, sollte auch diese neu berechnet werden, daraus die neue Höhe abgeleitet und mit den Anforderungen des Form-Resize verglichen werden. Es wird für Font dann der Größenwert genommen werden, der den Text des Controls gänzlich darstellt.

    Für die aktuelle Aufgabenstellung lässt sich das Ganze so abwandeln, das als Parameter der Funktion noch die ursprüngliche Bildschirmauflösung angegeben wird. Skalierungsmodi des Windows-Systems (hier 150%) sollten über die Abfrage von Screen.AllScreens(0) berücksichtigt sein.
    Hier mal eben ein Ansatz, einfach im Konstruktor o.ä. aufrufen.

    VB.NET-Quellcode

    1. Private Sub resize()
    2. Dim screenWidth As Double = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width
    3. Dim screenHeight As Double = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height
    4. Dim x As Double = Convert.ToDouble(Width / Me.Width)
    5. Me.Width = Convert.ToInt32(Me.Width * x)
    6. Me.Height = Convert.ToInt32(Me.Width * x)
    7. For Each ctrl As Control In Me.Controls
    8. ctrl.Width = Convert.ToInt32(ctrl.Width * x)
    9. ctrl.Height = Convert.ToInt32(ctrl.Height * x)
    10. ctrl.Location = New Point(Convert.ToInt32(ctrl.Location.X * x), Convert.ToInt32(ctrl.Location.Y * x))
    11. Next
    12. End Sub



    @us4711 war schneller, und seine Lösung hat auch schon die Schrift-Anpassung implementiert.
    Wenn das Leben wirklich nur aus Nullen und Einsen besteht, dann laufen sicherlich genügen Nullen frei herum. :D
    Signature-Move 8o
    kein Problem mit privaten Konversationen zu Thema XY :thumbup:
    Suchst Du das hier ....

    Komplette Form ist unscharf
    -... .-.. .- -.-. -.- ... .--. .. -.. . .-.
    The Leading Horse is white - the second horse is red - the third one is a black - the last one is a green.
    Hallo,

    erstmal Danke an alle für die Antworten / Vorschläge.

    Das resizen alle Controls funktioniert, ein Weiteres Problem wäre aber noch die Schrift!

    Eine Möglichkeit bei jedem Start der Anwendung die Auflösung abzufragen.

    Ist das die einzige Lösung unter Windows Forms?

    Ich stell mir das sehr mühsam vor da ich z.B. bei einer Anwendung mehr als 20 Controls habe und ich jedes einzelne je nach Auflösung anpassen müsste.

    Außerdem müsste man ja dann noch alle Skalierungsarten beachten (125%, 150%, 175%, 200%) oder?

    LG Raffael

    RevangeXX schrieb:

    und ich jedes einzelne je nach Auflösung anpassen müsste
    Das sollte in einer einzigen Schleife über alle relevanten Controls gehen.
    Beachten musst Du alles Mögliche.
    Wichtig ist daher, dass Du alles testest.
    Das Beste wäre, Du hättest ein Studio auf jedem relevanten System. Vielleicht genügt es, wenn Du Dir ein Testprogramm amchst mit einem oder zwei zu testenden Controls und dazu eine Reihe von Controls, um die relevanten Properties zu verändern und am Ende abzuspeichern.
    Wenn Du das Programm auf allen relevanten Systemen laufen lässt und Du Deine Einstellungen gefunden hast, kannst Du diese in Dein eigentliches Projekt integrieren.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hey,

    vielen Dank für die Antwort.

    Ja das hab ich mir schon gedacht. Leider gibt es da gewisse Probleme z.B.

    Geräte mit einer Skalierung von 200%
    Monitore mit einer sehr hohen Auflösung z.B. 4K

    Keines der genanten Punkte habe ich selbst noch im Freundeskreis zur Verfügung.

    Es kann doch nicht sein das man sich als Programmierer jeden art von Monitor Kauf/Besorgen muss um sicher zu sein das die Anwendung auch passt?

    Außer dem habe ich wenn ich all das Berücksichtige, wie bereits zu Anfang beschrieben nach wie vor das Problem das Meine Anwendung, die ich mit z.B. 1300 x 700 Pixel auf einem Full-HD Monitor erstellt habe, schlicht und ergreifend zu groß für z.B. mein Notebook mit einer Skalierung von 150% ist.

    Und da ich nicht möchte das meine Anwendung in der Größe veränderbar ist, gibt es in diesem Fall wohl keine Lösung oder?

    LG Raffael
    Was ist, wenn du die Skalierung mit einarbeitest?
    Ich meine die Skalierung lässt sich ja auslesen, also sollte das auch keine Problem sein, das mit in die Berechnung der Größen der Elemente und der Form mit einfließen zu lassen.

    LG Acr0most
    Wenn das Leben wirklich nur aus Nullen und Einsen besteht, dann laufen sicherlich genügen Nullen frei herum. :D
    Signature-Move 8o
    kein Problem mit privaten Konversationen zu Thema XY :thumbup:

    RevangeXX schrieb:

    jeden art von Monitor Kauf/Besorgen
    musst Du nicht, die Pixelauflösung ist doch da egal.
    Du musst lediglich die Schreen-Einstellung des Systems ändern und dann testen.
    Wenn Du das nicht machen willst - dann nimm einen anderen Rechner.
    Wenn Du mehrere Einstellungen getestet und verstanden hast, kannst Du das ja mal verallgemeinern.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich habe mich nochmal rangesetzt und die Funktion aus Post #9 überarbeitet.



    VB.NET-Quellcode

    1. private void resize(int developDpi, int developWidth, int developHeight)
    2. {
    3. Graphics graphics = this.CreateGraphics();
    4. double dpiFactor = developDpi / graphics.DpiX;
    5. double screenWidth = Screen.PrimaryScreen.Bounds.Width;
    6. double screenHeight = Screen.PrimaryScreen.Bounds.Height;
    7. double formWidthFactor =Convert.ToDouble(screenWidth) / Convert.ToDouble(developWidth) * dpiFactor;
    8. double formHeightFactor =Convert.ToDouble(screenHeight) / Convert.ToDouble(developHeight) * dpiFactor;
    9. double formSizeFactorX = this.Width / formWidthFactor;
    10. this.Width = Convert.ToInt32(this.Width * formWidthFactor) ;
    11. this.Height = Convert.ToInt32(this.Height * formHeightFactor);
    12. foreach (Control ctrl in this.Controls) {
    13. ctrl.Width = Convert.ToInt32(ctrl.Width * formWidthFactor);
    14. ctrl.Height = Convert.ToInt32(ctrl.Height * formHeightFactor);
    15. ctrl.Font = new Font(ctrl.Font.FontFamily ,Convert.ToInt32(ctrl.Font.Size * formHeightFactor));
    16. ctrl.Location = new Point(Convert.ToInt32(ctrl.Location.X * formWidthFactor), Convert.ToInt32(ctrl.Location.Y * formHeightFactor));
    17. }
    18. }


    VB.NET-Quellcode

    1. public MainForm()
    2. {
    3. InitializeComponent();
    4. resize(96, 1920, 1080);
    5. }




    siehe Anhang, gleiches Projekt einmal unter 1920x1080 und einmal unter 1280x720.

    du übergibst der resize-Funktion die Werte, unter der du die Applikation erstellt hast. Diese Funktion ermittelt dann die Faktoren zwischen DPI und neuer Auflösung und ändert die Form, Controls und Font-Size.


    Kritik, Verbesserungen gern gesehen, da sich gern mal Denkfehler einschleichen.


    LG Acr0most
    Bilder
    • 1280x720.png

      137,55 kB, 1.282×682, 643 mal angesehen
    • 1920x1080.png

      184,49 kB, 1.922×1.040, 499 mal angesehen
    • default.png

      11,87 kB, 854×744, 722 mal angesehen
    Wenn das Leben wirklich nur aus Nullen und Einsen besteht, dann laufen sicherlich genügen Nullen frei herum. :D
    Signature-Move 8o
    kein Problem mit privaten Konversationen zu Thema XY :thumbup:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Acr0most“ ()

    Hallo,

    vielen Lieben Dank nachmals für eure Antworten.

    Da ich Anfänger bin empfinde ich das ganze wohl als sehr aufwendig nur um eine Anwendung gut aussehen zu lassen.

    Zu deinem Code:

    Acr0most schrieb:

    VB.NET-Quellcode
    public MainForm()
    {
    InitializeComponent();
    resize(96, 1920, 1080);
    }


    Leider kann ich mit C# überhaupt nichts anfangen, weiß also nicht genau wie das in meine Anwendung implementieren soll. Habe breits nach "vb.net resize funktion" gesucht, bei den Treffern wird etwas anderes beschreiben.

    Ich werde mir jedenfalls die ganze Sache nochmal in Ruhe anschauen.

    LG Raffael
    @RevangeXX Acr0most hat eine Sub resize gebaut und die wird an der von dir zietierten stelle einfach nur aufgerufen.
    Eins VB Sub ist in C# eine Void (also eine Function ohne Rückgabewert)
    There is no CLOUD - just other people's computers

    Q: Why do JAVA developers wear glasses?
    A: Because they can't C#

    Daily prayer:
    "Dear Lord, grand me the strength not to kill any stupid people today and please grant me the ability to punch them in the face over standard TCP/IP."

    RevangeXX schrieb:

    C# überhaupt nichts anfangen


    converter.telerik.com/
    auch für die Zukunft ;) Erspart dir Einiges.

    Wenn das Leben wirklich nur aus Nullen und Einsen besteht, dann laufen sicherlich genügen Nullen frei herum. :D
    Signature-Move 8o
    kein Problem mit privaten Konversationen zu Thema XY :thumbup: