Java Layout
Willemers Informatik-Ecke
Ereignisse und Listener Swing Kontrollelemente

Was ist ein Layout?

Ein Layout legt fest, in welcher Anordnung Kontrollelemente in ihre Container gesetzt werden. Die meisten Layouts wurden bereits in der AWT verwendet und es gibt keinen Grund, warum sie nicht auch bei Swing eingesetzt werden sollten.

Ein Layout wird mit der Funktion setLayout dem Container zugeordnet. Die Kontrollelemente werden dann per add-Funktion in das Layout gesteckt.

FlowLayout

Es werden alle Elemente von links nach rechts bis zum rechten Rand aufgefüllt und dann wird quasi zeilenweise nach unten gegangen. Das folgende Beispiel zeigt dies anhand einiger Buttons.
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.Container;
import java.awt.FlowLayout;

public class TestFlow extends JFrame {

    TestFlow() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Container pane = getContentPane();
        pane.setLayout(new FlowLayout());
        for (int i=0; i<12; i++) {
            pane.add(new JButton("Button " + i));
        }
        this.setSize(400, 300);
        this.setVisible(true);
    }

    public static void main(String[] args) {
       new TestFlow();
    }
}
Der Konstruktor von FlowLayout kann einen Parameter für die Ausrichtung erhalten. Dort können die Werte FlowLayout.LEADING, FlowLayout.CENTER oder FlowLayout.TRAILING verwendet werden. LEADING sorgt für eine Linksausrichtung, TRAILING für eine Orientierung am rechten Rand. CENTER ist der Defaultwert.

BorderLayout

Wie der Name schon vermuten läßt wird ein Rand um ein zentrales Element gelegt. Man hat dann eine Kopfzeile, eine Fußzeile, einen linken und einen rechten Rand.

Um die Benennung zu vereinfachen, werden die Bereiche analog zu einer Landkarte mit NORTH, SOUTH, EAST und WEST bezeichnet. Das mittlere Feld heißt CENTER. Da diese Konstanten von der Klasse BorderLayout definiert werden, muss deren Name voranstehen. In welchem Feld die Kontrollelemente positioniert werden, wird durch beim Aufruf der Methode add durch den ersten Parameter angegeben.

import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.Container;
import java.awt.BorderLayout;

public class TestBorder extends JFrame {

    TestBorder() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(400, 300);
        Container pane = getContentPane();
        pane.setLayout(new BorderLayout());
        pane.add(BorderLayout.NORTH, new JButton("Oben"));
        pane.add(BorderLayout.SOUTH, new JButton("Unten"));
        pane.add(BorderLayout.WEST, new JButton("Links"));
        pane.add(BorderLayout.EAST, new JButton("Rechts"));
        pane.add(BorderLayout.CENTER, new JButton("Mitte"));
        this.setVisible(true);
    }

    public static void main(String[] args) {
       new TestBorder();
    }
}

GridLayout

Das Grid legt ein Gitter an. Im Konstruktor wird die Zahl der Zeilen und der Spalten festgelegt. Durch Hinzufügen (add) werden die Elemente der Reihenfolge nach ins Grid gelegt, und zwar mit der ersten Zeile beginnend von links nach rechts.

Das GridLayout bietet sich an, wenn die anzuordnenden Elemente gleichartig sind.

Die Dimension des Grids wird im Konstruktor vorgegeben. Der erste Parameter legt die Anzahl der Zeilen, der zweite die Anzahl der Spalten fest.

Die Elemente werden einfach wie gehabt eingefügt. Dabei werden die Felder von links nach rechts und dann von oben nach unten aufgefüllt.

import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.Container;
import java.awt.GridLayout;

public class TestGrid extends JFrame {

    TestGrid() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Container pane = getContentPane();
        pane.setLayout(new GridLayout(6,2));
        for (int i=0; i<12; i++) {
            pane.add(new JButton("Button " + i));
        }
        pack();
        this.setVisible(true);
    }

    public static void main(String[] args) {
       new TestGrid();
    }
}

GridBagLayout

In der Praxis werden Elemente etwas komplexer angeordnet, als das bisher gezeigt wurde. Mit dem GridBagLayout sind auch komplexere Aufbauten möglich.

Insbesondere bei Eingabemasken, soll die Beschriftung idealerweise weniger Platz als die Eingabe anfordern.

Zu diesem Zweck wird beim GridBagLayout ein Objekt der Klasse GridBagConstraints verwendet, das bestimmt, wie das Element in der Maske positioniert wird. Das folgende Listing erzeugt eine Eingabemaske für Name, Adresse und E-Mail.

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.*;

public class GridBag extends JFrame {
    public static void main(String[] args) {
        new GridBag();
    }

    public GridBag() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GridBagLayout gbLayout = new GridBagLayout();
        GridBagConstraints gbCon = new GridBagConstraints();
        setLayout(gbLayout);
        gbCon.gridy = 0;
        String[] titel = {"Name", "Adresse", "E-Mail"};
        for (int i=0; i<titel.length; i++) {
            gbCon.gridx = 0;
            add(new JLabel(titel[i]), gbCon);
            gbCon.gridx = 1;
            add(new JTextField(30), gbCon);
            gbCon.gridy++;
        }
        pack();
        setVisible(true);
    }
}

Die Attribute von GridBagConstraints

BoxLayout

Das BoxLayout ist kein Erbstück aus AWT-Zeiten, sondern ist für Swing gemacht. Darum wird er auch nicht aus der AWT-Bibliothek importiert, sondern von Swing.
javax.swing.BoxLayout

\begin{verbatim}
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.Container;
import javax.swing.BoxLayout;

public class ErsterSwing extends JFrame {

    ErsterSwing() {
        this.setSize(400, 300);
        Container pane = getContentPane(); 
        pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS)); 
        JLabel anton = new JLabel("Anton"); 
        JLabel berta = new JLabel("Berta"); 
        JLabel caesar = new JLabel("Caesar"); 
        pane.add(anton); 
        pane.add(berta); 
        pane.add(caesar); 
        this.setVisible(true);
    }

    public static void main(String[] args) {
       new ErsterSwing();
    }
}
BoxLayout.X_AXIS      von links nach rechts
BoxLayout.LINE_AXIS
BoxLayout.Y_AXIS      von oben nach unten
BoxLayout.PAGE_AXIS

Eigenes Layout ohne Layout-Manager

Wird setLayout mit dem Parameter null aufgerufen, ist gar kein Layout aktiv.
pane.setLayout(null);
Nun werden die Kontrollelemente einfach hinzugefügt und überdecken sich in diesem Augenblick. Anschließend werden die einzelnen Kontrollelemente über deren Methode setBounds positioniert:
button.setBounds(xPos, yPos, breite, hoehe);
Der Haken an dieser Methode ist, dass sich die Absolutpositionen nicht danach richten, welchen Platzbedarf die Kontrollelemente haben. Auf diese Weise kann es dazu führen, dass die Beschriftungen nicht mehr lesbar sind, weil beispielsweise der Benutzer übergrößere Zeichensätze verwendet.
Ereignisse und Listener Swing Kontrollelemente