Layout in Windows.Forms

    • VB.NET

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

      Layout in Windows.Forms

      Die Winforms-Controls bieten einen enormen Umfang an Layout-Möglichkeiten, welche vorbildlich intuitiv im Form-Designer einzurichten sind.
      Der Form-Designer ist ein Wysiwyg-Editor (“What You See Is What You Get”) für die gesamte Oberfläche. Dieses geniale Tool ist, was das “Visual” vom Visual-Studio ausmacht, und kann man glaub als den Meilenstein der Entwicklung der Oberflächen-Programmiererung überhaupt betrachten.
      Bei der Layout-Entwicklung werden die LayoutContainer in Zusammenarbeit mit dem Docking-Feature eingesetzt, über welches alle Controls verfügen - nicht nur die LayoutContainer.
      Parallel zum Docking existiert auch noch das Anchoring-Konzept, was ich aber für weniger flexibel und leistungsfähig halte (darin wird mir auch gelegentlich widersprochen, also ich würde mich wirklich freuen, wenn einer sich die Mühe machte, mir Gegenentwürfe zu meinen Samples zu präsentieren, die vergleichbare Useability bieten).

      NebenBemerkung: Für einen Schnelleinstieg hab ich (inzwischen) in Post#6 2 Videos eingestellt. Ich denke, die "Visual"-Denke schnackelt man schneller, wenn mans mal sieht ("Visual" eben ;) ).

      Layout-Prinzipien
      Einige (meiner) Layout-Prinzipien sind:
      • die gesamte Oberfläche muß sizeable sein
        sowohl die Forms selbst als auch Arbeitsflächen innerhalb
      • kein Platz verschwenden
        also egal, ob das Form, oder nur ein Teilbereich vergrößert wird: Es sollen keine ungenutzten Lücken entstehen
      • keine Überlappungen
        vor allem darf nicht passieren, dass Controls durch Verkleinerungen irgendwo drunter geschoben werden, und ggfs. Für den User nicht mehr verfügbar sind. In komplizierten Szenarien ist das vlt. nicht optimal umsetzbar, aber dann muss es Scrollbars geben die dem User anzeigen: “Da ist noch mehr - und du kannst es jederzeit hervorholen”
      LayoutContainer
      Die LayoutContainer repräsentieren jeweils andere Unterkonzepte von Layouting:
      • Panel:
        könnte man als Panel-Layouting auffassen - hat keine weitere Funktion als eben eine Gruppe von Controls zu präsentieren
      • Groupbox:
        wie Panel - fügt noch bischen Grafik hinzu, und vor allem eine Beschriftung der in der Groupbox gruppierten Controls
      • SplitContainer:
        Splitter-Layouting: Zwischen 2 Panels liegt ein SplitBalken, mit dem der User das Verhältnis beider Flächen sich einstellen kann - entweder in ihrer Breite oder in ihrer Höhe
      • TableLayoutPanel:
        Table-Layouting: Man kann eine Tabelle definieren, und jede Zelle präsentiert ein Control. Das Sizing-Verhalten der Zeilen und Spalten ist differenziert einstellbar, also ob eine Zeile/Spalte in Breite/Höhe mitgeht, wenn der User die Abmaße der Gesamt-Tabelle verändert.
        Es können auch Zellen gemergt werden, sodaß ein Control auch mehrere Zellen überspannt. Dieses wird am Control eingestellt - nicht am TLP.
      • FlowlayoutPanel
        Flow-Layouting: die Controls sind einfach in Flussrichtung (zb nach rechts oder nach unten) aufgereiht - ist die reihe voll, gibt’s einen Zeilenumbruch (bzw. “Spaltenumbruch)
      • TabControl:
        Tabbed-Layouting: beliebig viele Panels liegen übereinander, wie Registerkarten. In einer Leiste darüber guckt von jeder Registerkarte der “Reiter” heraus, über den man die entsprechende Tabpage nach vorne holen kann.
        Tabcontrol ist also dazu da, die verfügbare Arbeitsfläche zu vervielfachen.
      Sample-Anwendung (VB2008)
      Ich habe meine LayoutSamples auf einem Tabcontrol organisiert, also das Sample-Form weist insgesamt eine komplexe Struktur auf.


      Im folgenden führe ich alle Controls, die auf dem TabControl plaziert sind, auf, und die Einstellungen, zT. kommentiert, wasse bewirken.
      Richtig verstehen kanns natürlich nur, wer das Sample runterlädt, und mit dem Sizing-Verhalten bischen rumspielt.
      Im Download enthalten ist diese Besprechung auch als Word-Dokument - vlt. bisserl leichter lesbar als die nun folgende Aufstellung

      Quellcode

      1. ● Tabpage1
      2. Komplexes Beispiel:
      3. Zeigt v.a. einerseits die Layout-Möglichkeiten des SplitContainer im Zusammenspiel mit dem Docking der enthaltenen Controls.
      4. Ausserdem einen Teil der Layout-Möglichkeiten von TableLayoutPanel.
      5. ● SplitContainer1:
      6. ◦ .Orientation.Horizontal
      7. ◦ .Dock.Fill
      8. ◦ .FixedPanel.Panel1
      9. bewirkt, dass bei horizontalem Resizing des Forms nur Panel2 seine Breite anpasst
      10. ● Groupbox1 (auf dem linken SplitPanel (alias "Panel1"):
      11. ◦ .Dock.Fill
      12. ● Label4:
      13. ◦ .Dock.Top
      14. bewirkt, dass das Label seine Breite an die Groupbox anpasst, in seiner Höhe aber konstant bleibt
      15. ◦ .AutoSize.False
      16. bei .AutoSize.True würde das Label das Docking ignorieren, und stattdessen seine Größe auf
      17. seinen Inhalt abstimmen
      18. ◦ .TextAlign.Center
      19. ● Treeview1:
      20. ◦ .Dock.Fill
      21. füllt den verbleibenden Rest der Groupbox aus (also abzüglich Label4). Dazu muß der Treeview im
      22. Vordergrund sein + kann man per Kontextmenü einstellen
      23. ● Groupbox2 (auf dem rechten SplitPanel (alias "Panel2"):
      24. ◦ .Dock.Fill
      25. ● SplitContainer2:
      26. ◦ .BackColor.LightSalmon (man sieht aber nur den Splitterbalken gefärbt, da alles andere überdeckt ist)
      27. ◦ .Orientation.Vertical
      28. ◦ .Dock.Fill
      29. ◦ .FixedPanel.Panel1
      30. bewirkt, dass bei vertikalem Resizing des Forms nur Panel2 seine Höhe anpasst
      31. ● Label3 (auf dem oberen SplitPanel (alias Panel1):
      32. ◦ .AutoSize.False, .Dock.Fill, .TextAlign.Center
      33. ● Groupbox3 (auf Panel2):
      34. ◦ .Dock.Fill
      35. ◦ .BackColor.Control, um die SplitContainer-BackColor zu überdecken
      36. ● TablelayoutPanel1 (auf Panel2):
      37. ◦ .Dock.Top
      38. ◦ innerhalb des TLP wird über die Zeilen und Spalten des TLP gelayoutet:
      39. ◦ 2 Zeilen, 2 Spalten
      40. ◦ beide Zeilen Percent 50%, also gleich hoch
      41. ◦ Column1: Absolute 98, also 98pix breit
      42. ◦ Column2: Percent 100%, also füllt die restliche Breite.
      43. Veränderungen der Breite des TLP, ob durch Form-Resizing, oder durch Betätigen des
      44. horizontalen Splitters bewirken also, dass sich Column2 anpasst, nicht aber Column1
      45. ● Richtextbox1:
      46. ◦ .Dock.Fill
      47. ● Tabpage2
      48. ● FlowLayoutPanel1:
      49. FlowlayoutPanel ist ein ContainerControl, in das man einfach andere Controls hineinschmeißen kann,
      50. und die werden dann im Grunde wie in Listbox aufgereiht präsentiert.
      51. Nachteil ist, dass die reingeworfenen Controls in ihren Abmaßen fix sein müssen, also zB kein Docking
      52. verwenden können,
      53. ◦ .Dock.Fill
      54. ● TableLayoutPanel2:
      55. ◦ .Dock.None
      56. ◦ nur eine Zeile und Spalte
      57. ● Button1:
      58. ◦ Anchor.None
      59. Dieser Trick bewirkt, dass der Button sich immer genau in der Mitte der TableLayout-Zelle zentriert.
      60. ● Button2 – Button5:
      61. beliebige TestControls zur Demonstration des Flow-Verhaltens des FlowlayoutPanels
      62. ● Tabpage3
      63. ● SplitContainer3:
      64. ● TablelayoutPanel3 (auf Panel1): 2 Columns, 3 Rows
      65. ◦ .Dock.Fill
      66. ◦ Column1: Absolute 52py
      67. ◦ Columns2: Percent 100%
      68. (also Spalte 2 folgt dem Sizing des TLP, Column1 ist fix)
      69. ◦ Row1: Absolute 25
      70. ◦ Row2 Absolute 25
      71. ◦ Row3 Percent 100%
      72. also nur Row3 folgt dem Sizing des TLP
      73. ● Label5+Label6:
      74. ◦ .Autosize.False, .Dock.Fill, .TextAlign.MiddleRight
      75. Text-Rechtsbündigkeit, um die Beschriftung den rechts davon liegenden Textboxen noch klarer
      76. zuzuordnen
      77. ● Textbox3 + Textbox4:
      78. ◦ .Dock.Fill
      79. ◦ .Multiline.False (einzeilige Textbox)
      80. einzeilige Textboxen haben ein spezifisches AutoSize-Verhalten: sie sind in Höhe fix
      81. ● Picturebox1:
      82. ◦ .Dock.Fill
      83. ◦ .ColumnSpan = 2
      84. Die Picturebox überspannt beide Spalten des TablelayoutPanels
      85. ◦ .Sizemode.Zoom
      86. das Bild wird komplett und unverzerrt zentriert in der Picturebox angezeigt.
      87. ● FlowlayoutPanel2 (auf Panel2):
      88. ◦ .Dock.Fill
      89. ● Panel1, Panel2:
      90. (diese Panels fassen jeweils eine Textbox zusammen mit einem Label zur Beschriftung)
      91. ● Jeweils Label:
      92. ◦ .Dock.Left, .TextAlign.MiddleRight
      93. ● jeweils Textbox:
      94. ◦ .Dock.Fill
      95. ● Picturebox2
      96. ● Groupbox4, darin Picturebox3

      Ansicht "DokumentenGliederung"
      Den Struktur-Aufbau eines Forms kann man sich wunderbar in der Ansicht "Menu-WeitereFenster-Dokumentengliederung" angucken – dort hat man alle Controls zur Ansicht, direkt zugreifbar, und kann sie sogar von einem Container in einen anneren verschieben:

      Dateien

      Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „ErfinderDesRades“ ()

      (darin wird mir auch gelegentlich widersprochen, also ich würde mich wirklich freuen, wenn einer sich die Mühe machte, mir Gegenentwürfe zu meinen Samples zu präsentieren, die vergleichbare Useability bieten)

      :D
      Ich benutze Anchor sehr gerne bei Buttons, da diese oft nicht größer sein müssen, als der Text den sie enthalten, somit ist es ohne großen Aufwand ganz einfach möglich diese rechts anzudocken, aber nicht die ganze Seite ausfüllen.
      nehmen wir nun an, ich möchte noch eine Listbox(nichts weiter) links von den Buttons platzieren, dann geht das mit Anchor auch ganz geschickt und ich habe überall von der Form einen schönen 12px(Default) Abstand(und die ListBox wird auch der größe angepasst), ohne dass ich wirklich viel Aufwand habe, Natürlich könnte ich das ganze auch mit einem SplitContainer machen, aber bei solch banalen Dingen, die nicht sehr Aufwändig sind und nicht sonderlich viel Dynamik benötigen, ist das denke ich mehr als genug.

      Außerdem geb ich meinem Formular gerne eine MinimumSize, da für mich jenachdem kleinere größen keinen Sinn ergeben...
      Ich wollte auch mal ne total überflüssige Signatur:
      ---Leer---
      das ging je schnell mit dem widersprechen ;)
      Wie gesagt: ich halte Anchoring in komplexen Szenarien für zuwenig leistungsfähig - in einfacheren Fällen kommt man damit auch klar.
      Ich bin mir auch nicht sicher, ob man das ganze Theater nicht auch mit Anchoring hinkriegen würde, vlt. mit nichtmal viel mehr Aufwand.
      Weil ich nutze Docking durchgängig.
      Aber zB dieses kleine Szenario: 3 Richtextboxen sollen untereinander angeordnet sein, dabei die verfügbare Breite ausfüllen.
      Mit Docking stelle ich jede der Rtbs auf Dock.Top und fertig.
      Mit Anchoring positioniert man sie fein, und setzt die Anchors.
      Und nun stellste fest: die oberste Rtb ist zu klein - die soll höher.
      Bei Docking ziehe ich sie eben größer und fertig, während bei Anchoring sie nach dem vergrößern nun die nächste Rtb verdeckt. Die kannste natürlich nach unten verschieben - nur dann verdeckt sie ihrerseits die folgende Rtb. Usw...

      Zu MinimumSize stimme ich zu - ist ganz allgemein ein wesentliches Layout-Mittel.
      Man markiere beide Textboxen und vergrößere dabei die erstere und siehe da die zweite wird automatisch verkleinert - das System funktioniert schon genial. Und mit Docking Top, bekommt man zwischen den Controls halt keinen Abstand, mit Anchor schon. Aber ich meinte natürlich bei nicht komplexen Szenarien, wobei ich zugeben muss, dass ich TableLayout eigt. nie verwende und das meiste mit Anchor mache ;)
      Ich wollte auch mal ne total überflüssige Signatur:
      ---Leer---
      habichnich gewußt.
      Ich würde was mit Margin und DockPadding unternehmen - neben Minimum-/Maximum-Size weitere wesentliche Layout-Mechanismen, auf die man eiglich noch richtig eingehen müsste.
      Kurz: Margin definiert den Abstand eines Controls zum nächsten (also nach aussen), und DockPading definiert einen Abstand zwischen einem LayoutContainer und seinen Inhalten (also nach innen).

      Margin funktioniert leider nicht in allen Szenarien richtig. Also im FlowlayoutPanel funztes, aber glaub beim Docking wirds ignoriert.