Swing CardLayout - kein Wechsel möglich

AleexQo

Mitglied
Hallo,

Ich habe ein Programm geschrieben, in dem ein JFrame (mit BorderLayout) geöffnet wird. Dieses JFrame besitzt 2 Panels, eines davon habe ich mit Hilfe des BorderLayouts am unteren Rand platziert (BorderLayout.SOUTH), das andere im Center.
Dem oberen Panel habe ich ein CardLayout zugewiesen, und wollte dieses dann über das untere Panel steuern. In dem unteren Panel habe ich 4 Buttons implementiert.

1. Wenn ich dem Panel mit dem CardLayout nun weitere Panel hinzufüge, tut sich nichts. Geht das etwas nicht?
2. Wenn ich dem Panel mit dem CardLayout Buttons hinzufüge, ignoriert es die Größe des Knopfes und durchschalten lässt es sich auch nicht. Was ist bei meinem Code falsch?

Beim ausführen des Programms wird nur ein großer Knopf angezeigt auf dem "eerster Knopf" steht und unten sind die 4 Knöpfe, welche anscheinend ohne Funktion sind.


Mein Code:

Java:
package test;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;

public class testmain extends JFrame {

    CardLayout cardLayout;
    JButton btnPrev;
    JButton btnNext;
    JButton btnFirst;
    JButton btnLast;
    JButton btn5;
    JPanel panelMain;

    public static void main(String[] args) {
        JFrame jf = new testmain();
    }

    public testmain() {

        // JFrame Einstellungen
        setVisible(true);
        setSize(800, 500);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(new BorderLayout());

        // JPanels erzeugen, zum Testen vom CardLayout
        JPanel panelRot = new JPanel();
        JPanel panelBlau = new JPanel();
        JPanel panelGelb = new JPanel();
        JPanel panelSchwarz = new JPanel();

        // Hintergrundfarbe für die Panels
        panelRot.setBackground(Color.RED);
        panelBlau.setBackground(Color.BLUE);
        panelGelb.setBackground(Color.YELLOW);
        panelSchwarz.setBackground(Color.BLACK);

        // die 2 HauptJPanels
        JPanel panelBtn = new JPanel();
        JPanel panelMain = new JPanel();

        add(panelBtn, BorderLayout.SOUTH);
        add(panelMain, BorderLayout.CENTER);
        panelBtn.setLayout(new FlowLayout());

        // CardLayout für das große Panel erstellen
        CardLayout cardLayout = new CardLayout();
        panelMain.setLayout(cardLayout);

        // Hinzufügen der Buttons zum unteren Panel
        JButton btnPrev = new JButton("<");
        JButton btnNext = new JButton(">");
        JButton btnFirst = new JButton("Erstes");
        JButton btnLast = new JButton("Letztes");

        panelBtn.add(btnPrev);
        panelBtn.add(btnNext);
        panelBtn.add(btnFirst);
        panelBtn.add(btnLast);

        // ActionListener für die Buttons
        BtnListener aLi = new BtnListener();

        btnPrev.addActionListener(aLi);
        btnNext.addActionListener(aLi);
        btnFirst.addActionListener(aLi);
        btnLast.addActionListener(aLi);

        // Hintergrundfarbe zur besseren Sichtbarkeit
        panelBtn.setBackground(Color.RED);
        panelMain.setBackground(Color.YELLOW);

        // Elemente für das CardLayout
        // panelMain.add(panelRot, "Rot");
        // panelMain.add(panelBlau, "Blau");

        JButton knopf1 = new JButton("eerster Knopf");
        knopf1.setSize(50, 15);

        panelMain.add(knopf1, "button1");
        panelMain.add(new JButton("zweiter Knopf"), "button2");
        panelMain.add(new JButton("dritter Knopf"), "button3");
        panelMain.add(new JButton("vierter Knopf"), "button4");

        setSize(500, 300);
        setLocationRelativeTo(null);

        setVisible(true);

    }

    // ActionListener für die Buttons im unteren Panel
    private class BtnListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {

            // nächstes Element im CardLayout
            if (e.getSource().equals(btnNext)) {
                cardLayout.next(panelMain);
                // vorheriges Element im CardLayout
            } else if (e.getSource().equals(btnPrev)) {
                cardLayout.previous(panelMain);
                // erstes Element
            } else if (e.getSource().equals(btnFirst)) {
                cardLayout.first(panelMain);
                // letztes Element
            } else if (e.getSource().equals(btnLast)) {
                cardLayout.last(panelMain);
            }
        }

    }

}

PS: Das ist nur eine Testklasse, deshalb sind kleine "unwichtige" Fehler wie z.B. der kleingeschriebene Klassenname enthalten.
 
Du musst das machen was du hier auskommentiert hast:
// Elemente für das CardLayout
// panelMain.add(panelRot, "Rot");
// panelMain.add(panelBlau, "Blau");

Damit sind deine Panels dem Layout bekannt und du kannst sie z.B. per "cardLayout.next(panaleMain)" steuern.
 
Es gibt sehr viele Dinge, die man hier verbessern kann:
1. Man erbt nicht von JFrame, wenn man nicht die Funktionalität verändern möchte, d.h. das ist erst notwendig, wenn man Methoden überschreiben möchte.
2. Du erstellst oft lokale Variablen mit dem gleichen Namen wie die Attribute. Dadurch werden Instanzattribute "überschattet". Wenn du auf das Attribut verweisen möchtest, darfst du nicht nochmal den Typ deklarieren. Siehe etwa: http://www.dummies.com/programming/java/shadowed-classes-or-variables-in-java/
3. "setSize" sollte man nicht verwenden. Es funktioniert zwar, wenn man ein "null"-Layout verwendet, aber das sollte man nicht. Stattdessen sollte man setPreferredSize setzen und die genaue Größe vom Layoutmanager bestimmen lassen.
4. Das "CENTER" in einem BorderLayout gibt seinen Komponenten immer das maximal-Mögliche an Platz, deswegen wird die setSize nicht beachtet.

Ich habe deinen Code mal "erweitert" wie du vermutlich vorhattest:

Java:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Testmain extends JFrame {

    CardLayout cardLayout = new CardLayout();
    JPanel panelMain = new JPanel(cardLayout);
    JButton btnPrev = new JButton("<");;
    JButton btnNext = new JButton(">");
    JButton btnFirst = new JButton("Erstes");
    JButton btnLast = new JButton("Letztes");;

    JPanel colorPanels[] = new JPanel[4];
    Color colors[] = { Color.RED, Color.BLUE, Color.YELLOW, Color.BLACK };

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

    public Testmain() {
        setSize(800, 500);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(new BorderLayout());

        JPanel innerPanel = new JPanel();
        innerPanel.add(panelMain);
        add(innerPanel);

        JPanel panelBtn = new JPanel(new FlowLayout());
        panelBtn.add(btnPrev);
        panelBtn.add(btnNext);
        panelBtn.add(btnFirst);
        panelBtn.add(btnLast);
        add(panelBtn, BorderLayout.SOUTH);

        btnPrev.addActionListener((ActionEvent e) -> cardLayout.previous(panelMain));
        btnNext.addActionListener((ActionEvent e) -> cardLayout.next(panelMain));
        btnFirst.addActionListener((ActionEvent e) -> cardLayout.first(panelMain));
        btnLast.addActionListener((ActionEvent e) -> cardLayout.last(panelMain));

        panelBtn.setBackground(Color.RED);
        panelMain.setBackground(Color.YELLOW);
        innerPanel.setBackground(Color.GREEN);
        String[] names = { "erster", "zweiter", "dritter", "vierter" };
        JButton[] btns = new JButton[4];
        for (int i = 0; i < 4; i++) {
            colorPanels[i] = new JPanel();
            colorPanels[i].setBackground(colors[i]);
            btns[i] = new JButton(names[i] + " Knopf");
            btns[i].setPreferredSize(new Dimension(100, 15 * i + 15));
            colorPanels[i].add(btns[i]);
            panelMain.add(colorPanels[i]);
        }
        setSize(500, 300);
        setLocationRelativeTo(null);
        pack();
        setVisible(true);

    }

}
Hierbei hab' ich mal die Kurzschreibweise für die ActionListener verwendet. Das funktioniert ab Java 8 und heißt Lambda-Ausdruck. (Ist nicht so wichtig, aber ich mag sie 😉 )
 
@X5-599 :
das habe ich nur auskommentiert, weil es nicht funktioniert hat und ich es dann mit Buttons versuchen wollte.

@JCODA :
1. Normal erbe ich nur von JFrame wenn ich den Namen des JFrames mittels "super("name");" eingebe. Reicht das oder sollte ich es auch dann nicht machen?
2./3./4. Wieder etwas gelernt, danke🙂

Zum Code:
Danke dafür, dass du dir die Zeit genommen hast! Es funktioniert und dein Code ist viel kürzer. Habe durch deinen Code auch wieder einige Sachen gelernt, so kann ich jeden Code von mir nochmal um ein Stück verkürzen. Danke!!😀
 
Habe noch ein paar kurze Fragen zum Code:
Am anfang steht:
setSize(800, 500);
1. wenn ich die Werte verändere. Tut sich garnichts.
2. im letzten Abschnitt steht setSize(500, 300);, wenn ich diese Werte verändere verschiebt sich das JFrame nur, jedoch ändert es die Größe nicht. Wieso?
-->
1./2. Kann ich die Größe des JFrames nur ändern, wenn ich die Größe der JPanels verändere?

3. die Methode pack() packt die Componenten des JFrames anhand der preferredSize, damit das JFrame alles anzeigt, habe ich das richtig verstanden?
 
1. Normal erbe ich nur von JFrame wenn ich den Namen des JFrames mittels "super("name");" eingebe. Reicht das oder sollte ich es auch dann nicht machen?
Das ließe sich auch durch Übergabe an den "normalen" Konstruktor bewerkstelligen: JFrame frame = new JFrame("name");


setSize(800, 500);...
pack()
Ups, stimmt, da hab ich etwas vergessen:
pack() packt das JFrame so, dass alle Komponenten nach ihrer preferredSize genügend Platz haben, das stimmt. Deshalb funktioniert setSize nichtmehr.
Ich erstelle meistens ein JPanel als "ContentPane", sodass nur dieses eine dem JFrame hinzugefügt wird. Diesem gebe ich meist eine preferredSize.
Eine ContentPane kann man mit der Methode setContentPane(jpanel) setzen.
 

Zurück
Oben