Was ist ein CardLayout?

Ein CardLayout ermöglicht das abwechselnde Laden unterschiedlicher Komponenten in einem und demselben Bereich des GUI.

Um an gleicher Position innerhalb eines Fensters wechselnde Komponenten anzeigen zu können, kann, außer einem JTabbedPane, auch ein CardLayout zum Einsatz kommen. Die dem Layout zugewiesenen Komponenten bilden hierbei, ähnlich einem Stapel von Spielkarten, eine Menge von Elementen, von denen immer nur eines sichtbar ist. Der Layout-Manager bietet hierbei eine Reihe von Methoden, mit deren Hilfe zwischen den einzelnen Komponenten gewechselt werden kann.

Das Beispiel zeigt ein einfaches Fenster, das innerhalb eines CardLayout vier Jlabel geladen hat, zwischen deren Anzeige mit einem Button gewechselt werden kann. Die Label 3 und 4 befinden sich hierbei in einem gesonderten Panel, das die Komponenten nach seinem Standard-Layout (FlowLayout) anordnet.

public class CardLayoutBsp {

    public CardLayoutBsp() {
        init();
    }

    private void init() {
        JFrame frame = new JFrame();
        CardLayout cl = new CardLayout();
        JPanel mainPanel = new JPanel(cl);
        frame.add(createMainPanel(mainPanel), BorderLayout.CENTER);
        JButton nextButt = new JButton("wechseln");
        nextButt.addActionListener(e -> cl.next(mainPanel));
        frame.add(nextButt, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle("CardLayout");
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private Component createMainPanel(JPanel panel) {
        panel.add(createLabel("eins", new Color(250,180,180)));
        panel.add(createLabel("zwei", new Color(180, 250, 180)));
        JPanel subPanel = new JPanel();
        subPanel.add(createLabel("drei", new Color(180, 180, 250)));
        subPanel.add(createLabel("vier", new Color(180, 180, 180)));
        panel.add(subPanel);
        return panel;
    }

    private JLabel createLabel(String nr, Color c) {
        JLabel label = new JLabel(nr, SwingConstants.CENTER);
        label.setOpaque(true);
        label.setBackground(c);
        label.setFont(new Font("Sans", Font.BOLD, 20));
        label.setText(nr);
        return label;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new CardLayoutBsp());
    }
}
Card-Layout mit JLabel Card-Layout mit JPanel

Beim Ändern der Fenstergröße zeigt sich, dass die geladenen Komponenten auf die Größe der Card angepasst werden, sofern deren Maximalgrößen dies erlauben.

Wechsel zwischen den Ansichten

Für das Wechseln zwischen den Karten stellt CardLayout eine Reihe an Methoden bereit. Sie benötigen alle den Container, der das CardLayout verwaltet, als Parameter.

next(Container)
Wechselt zur nächsten Karte
previous(Container)
Wechselt zur vorherigen Karte
first(Container)
Wechselt zur ersten Karte
last(Container)
Wechselt zur letzten Karte
show(Container, String)
Wechselt zur durch das zweite Argument angegebenen Komponente. Hierzu muss diese beim Hinzufügen zum Container durch add() mit einem String identifitiert werden. Die Angabe eines vergebenen Komponentennamens reicht nicht!

Die folgende Methode bewirkt die initiale Anzeige der Karte mit den Labeln "drei" und "vier" durch Aufruf der Methode show():

private Component createMainPanel(JPanel panel) {
    panel.add(createLabel("eins", new Color(250,180,180)));
    panel.add(createLabel("zwei", new Color(180, 250, 180)));
    JPanel subPanel = new JPanel();
    subPanel.add(createLabel("drei", new Color(180, 180, 250)));
    subPanel.add(createLabel("vier", new Color(180, 180, 180)));
    panel.add(subPanel, "sub");
    ((CardLayout)panel.getLayout()).show(panel, "sub");
    return panel;
}

Das folgende Vorgehen bleibt demgegenüber wirkungslos. Die erste Karte wird initial gezeigt:

private Component createMainPanel(JPanel panel) {
    panel.add(createLabel("eins", new Color(250,180,180)));
    panel.add(createLabel("zwei", new Color(180, 250, 180)));
    JPanel subPanel = new JPanel();
    subPanel.add(createLabel("drei", new Color(180, 180, 250)));
    subPanel.add(createLabel("vier", new Color(180, 180, 180)));
    subPanel.setName("sub");
    panel.add(subPanel);
    ((CardLayout)panel.getLayout()).show(panel, subPanel.getName()); // wirkungslos
    return panel;
}

Abstände

Bei einem CardLayout-Container ist immer nur eine der geladenen Komponenten sichtbar. Alle anderen, mit add() eingefügten Komponenten kann man sich als im Stapel weiter unten versteckt vorstellen.1 Die beiden Methoden setHgap(int) bzw. setVgap(int) steuern somit nicht, wie in den Apidocs zu den Methoden [2] angegeben, den horizontalen oder vertikalen Abstand zwischen den Komponenten, sondern bilden hier vielmehr den Abstand zum Containerrand.
Die Angaben gelten für den gesamten Gültigkeitsbereich des CardLayout. Sollen Abstände individuell unterschiedlich behandelt werden, so bietet es sich an, die fraglichen Komponenten zunächst in gesonderte Container mit eigenen Layout-Managern zu laden.

//...
CardLayout cl = new CardLayout();
cl.setHgap(100);
cl.setVgap(30);
//...

Card-Layout mit JLabel und Abständen, leicht aufgezogen Card-Layout mit innerem JPanel und Abständen, leicht aufgezogen
Quellen
  1. How to Use CardLayout
  2. https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/java/awt/CardLayout.html#setHgap(int)

1) Dies bezieht sich nur auf die direkt eingefügten Komponenten. Selbstverständlich können, wie im Beispiel zu sehen, auch Komponenten geladen sein, die wiederum weitere Komponenten enthalten.