Sonntag, 5. Juli 2009

GUIs in Java: Andere Layouts

Letztes mal haben wir ein bisschen mit Layouts gespielt, und dabei zwei BorderLayouts verwendet.

BorderLayout ist aber bei weitem nicht das letzte und mächtigste, das Java zu bieten hat:

FlowLayout:
FlowLayout kann man wirklich nicht als mächtig bezeichnen. Wichtig ist es allerdings, weil es das Standardlayout für Panels und Applets ist. Wenn in deinem Applet der Inhalt nur sehr klein erscheint, könnte es sein, dass du vergessen hast ein BorderLayout einzustellen. Denn das FlowLayout streckt den Inhalt nicht über den gesamten Component.
Alle Komponenten, die mit einem FlowLayout verwaltet werden (vergiss dabei nicht, dass das Layout immer auf einen Component angewendet wird, und diesem dann die Child-Components hinzugefügt werden), werden hintereinander in einer Zeile dargestellt. Ist die erste Zeile voll, wird in der nächsten weitergemacht.

Hier sieht man auch, wie die Zeilenhöhe zustandekommt: der höchste Component jeder Zeile bestimmt die Höhe der Zeile.

GridLayout:
GridLayout geht schon eher in die Richtung mächtig. GridLayout ermöglicht es, beliebig viele Komponenten in eine rechteckigen Gitter anzuordnen. Jeder Component erhält dabei genau gleich viel Platz.

Für dieses GridLayout wurden als Parameter als Zeilen- und Spaltenzahl 3 angegeben. Es hätte aber eine Angabe genügt (dafür nimmt man als den zweiten Parameter 0). Gibt man nur die Spaltenzahl an, wird die Zeilenzahl durch die Anzahl der Kind-Components bestimmt und andersherum.

BoxLayout:
BoxLayout hat Gemeinsamkeiten mit FlowLayout, ist aber um einiges nützlicher: In einem BoxLayout kann man die Komponenten in einer Zeile oder einer Spalte ausrichten.
In einem Spaltenorientierten BoxLayout hat jeder Component seine preferred height, und die breite wird (soweit möglich) an den breitesten component angepasst. In ähnlicher Art gilt das eben für zeilenorientierte BoxLayouts.

hier habe ich ein bisschen nachgeholfen. Das BoxLayout verwendet 3 Einstellungsmöglichkeiten eines Component: minimum size, maximum size und preferred size. Die maximum size eines Buttons ist standardmäßig genau so groß wie die preferred size. Damit diese Buttons auf gleiche Länge gestreckt werden, musste ich die maximum size manuell vergrößern.

CardLayout:
CardLayout ist ein spezielles Layout, das von allen hinzugefügten Components immer nur einen darstellt. Es könnte einmal eine Situation geben, wo du es brauchst, aber wahrscheinlich ist dann eine JTabbedPane sowieso die bessere Wahl. JTabbedPane stelln nämlich gleich die Registerkarten bereit, um zwischen den Tabs zu wechseln.


Darüber hinaus gibt es noch mehr, mächtigere Layouts, zum Beispiel:
GridBagLayout
GroupLayout
SpringLayout
Diese sind aber recht kompliziert zu verwenden und hauptsächlich für grafische Editoren gedacht.


Ein einzelnes Layout führt allerdings selten zum Ziel. Meistens wird man Panels mit verschiedenen Layouts Schachteln, um zum erwünschten Ergebnis zu kommen. Als Beispiel hier ein Formular, in das beliebig viele Eingabefelder eingefügt werden können:

Hier werden 3 Ebenen verwendet: Ganz oben ein BorderLayout. Der Button ist im South-Bereich, in der Mitte ist ein Panel für den Rest. Dieses Panel benutzt ein BoxLayout, in dem die Komponenten untereinander ausgerichtet ist.
Jede Zeile im BoxLayout stellt eine Eingabe dar. Weil ein BoxLayout beliebig viele Components enthalten kann, ist diese Struktur sehr flexibel.
Jede Eingabe ist wieder ein Panel mit BorderLayout. Das Label braucht nicht größer zu werden, deshalb ist es im West-Bereich. Das Eingabefeld soll den restlichen Platz verbrauchen und ist im Center-Bereich.

Solche komliziertere Layouts könnte man auch mit einem der oberen Layouts (GridBag, Group, Spring) realisieren, aber ohne einen Code-Editor sind verschachtelte Layouts ziemlich sicher schneller, kürzer und übersichtlicher, als eines dieser Layouts zu benutzen.

Für das letzte Beispiel gibts hier nochmal den Code:

package post02;


import java.awt.BorderLayout;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;


public class Form extends JPanel {
public static void main(String[] args) {
JFrame jf = new JFrame();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//Ein Array kann man bei der Deklaration der Variable so initialisieren:
//String[] s = {...};
//Wenn man nicht gerade eine Variable deklariert kann man aber auch
//new String[] {...}
//benutzen.
jf.add(new Form(new String[] {"Vorname:", "Nachname:", "Adresse:"}));

jf.pack();
jf.setVisible(true);
}

private String[] labels;
private JTextField[] textFields;
private JButton ok;

public Form(String[] labels) {
super(new BorderLayout());

this.labels = labels;
textFields = new JTextField[labels.length];

JPanel form = new JPanel();
//Der Konstruktor von BoxLayout nimmt (im Gegensatz zu den anderen üblichen Layouts) auch den Component,
//mit dem es verwendet werden soll. Deshalb kann man das BoxLayout auch noch nicht im Konstruktor von
//JPanel angeben
form.setLayout(new BoxLayout(form, BoxLayout.Y_AXIS));
for(int i = 0; i < labels.length; i++) {
JLabel l = new JLabel(labels[i]);
textFields[i] = new JTextField(5);

JPanel p = new JPanel(new BorderLayout());
p.add(l, BorderLayout.WEST);
p.add(textFields[i]);
form.add(p);
}

add(form);
//hier wird gleichzeitig eine Zuweisung gemacht und die Variable abgefragt. Das ist also das gleiche wie
//ok = new JButton("OK");
//odd(ok, ...);
add(ok = new JButton("OK"), BorderLayout.SOUTH);
}
}

3 Kommentare:

  1. CardLayout: kann durchaus praktisch sein, denk an typische assistenten-fenster (zb bei einer installation). da könntest du den inhalt, der sich im gui verändert ins cardlayout geben und sobald der benutzer auf den "weiter"-button klickt, wird im cardlayout umgeschaltet. okay, ist aber doch eher n spezialfall ;)

    was wirklich praktisch (wenn auch etwas tippaufwändig) ist, ist das GridBagLayout. damit kannst du layouttechnisch schon einiges erreichen.

    auch hier der hinweis: es gibt noch andere gui-libraries wie SWT, die dann auch andere layouts verwenden ;)

    AntwortenLöschen
  2. wie gesagt, die situation legt die maßnahmen fest. so ein ähnliches prinzip habe ich mal bei einer bilder-slideshow verwendet, ist aber eben auch schon ein bissl her ;)

    GridBagLayout kann sicherlich oft praktisch sein. Mehrere Zellen verbinden wollte ich, glaube ich, schon öfters, aber auch wenn man nicht alle Zellen belegen will, ist es praktisch.
    Gehe ich richtig davon aus, dass beim GridBagLayout alle zellen gleich groß sind? den nachteil spüre ich ziemlich oft...

    mit SWT hab ich allerdings wenig erfahrung, deswegen wirst du bei mir wenig drüber hören ;)

    AntwortenLöschen
  3. hm hab selbst lange keine größeren swing-guis gemacht, kann ich dir also grad gar nicht sagen, ob die spalten/zeilen variabel groß sein können.

    seit ich SWT und das FormLayout kennengelernt habe, verwende ich nichts anderes mehr :P

    AntwortenLöschen