Search code examples
javaswinguser-interfacelayout-managercardlayout

CardLayout not switching cards


First of all I am not getting any errors. So it's probably a logical error. I am trying to switch to the playMenu panel but when i press the button (which is in the mainMenu class) nothing happens. Yes the method switchCard is being called since I checked it with a simple println.

This is my Frame class which holds the content panel.

I removed variables that are not related.

//Panel Final Names
    private final String MENU_ID = "menu";
    private final String PLAY_ID = "play";

    //Panels(Cards)
    private MainMenu mainMenu;
    private Play playMenu;

    //JFrame
    private JFrame frame = new JFrame("Battleships");

    //Panel that will hold the card panel
    private CardLayout cl = new CardLayout();
    private JPanel contentPanel = new JPanel(cl);

    //Constructors
    public Frame(){}

    public Frame(boolean x){
        GUI();
    }

    public void GUI(){
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);

        /*
            Passing Parameters to MainMenu class so
            you can do operations like changing panels and
            disposing the main JFrame from a different class
        */
        mainMenu = new MainMenu(frame, contentPanel);
        playMenu = new Play(frame, contentPanel);

//Adding menu panel as a card in contentPanel
        contentPanel.add(mainMenu, MENU_ID);
        contentPanel.add(playMenu, PLAY_ID);

        //Adding contentPanel to JFrame
        frame.add(contentPanel, BorderLayout.CENTER);

        frame.pack();
        frame.setVisible(true);


    }

    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                new Frame(true);
            }
        });
    }

    public void switchCard(){
        contentPanel.setLayout(new CardLayout());
        CardLayout cl = (CardLayout) contentPanel.getLayout();
        cl.show(contentPanel, PLAY_ID);
    }

This is the JPanel that I want to switch to. I removed the auto-generated code that NetBeans makes. If it's relevant for this problem in some way I will post it.

public class Play extends javax.swing.JPanel {

    /**
     * Creates new form Play
     */

    private JFrame parentFrame;
    private JPanel contentPanel;

    public Play(JFrame frameIn, JPanel panelIn) {
        initComponents();
        contentPanel = panelIn;
        parentFrame = frameIn;
    }

}


Solution

  • This won't work:

    public void switchCard(){
        contentPanel.setLayout(new CardLayout());
        CardLayout cl = (CardLayout) contentPanel.getLayout();
        cl.show(contentPanel, PLAY_ID);
    }
    

    because you're changing the layout from the original one, the one that holds all the data. Instead, don't set the contentPane's layout but use the one already there.

    public void switchCard(){
        // contentPanel.setLayout(new CardLayout());
        CardLayout cl = (CardLayout) contentPanel.getLayout();
        cl.show(contentPanel, PLAY_ID);
    }
    

    For that matter, you could just use the cl field that you already have. For example:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class BattleShipSwap {
       // make id's public
       public static final String MENU_ID = "menu";
       public static final String PLAY_ID = "play";
    
       private MainMenu mainMenu;
       private Play playMenu;
    
       private JFrame frame = new JFrame("Battleships");
    
       private CardLayout cl = new CardLayout();
       private JPanel contentPanel = new JPanel(cl);
    
       public BattleShipSwap() {
          initGui();
       }
    
       public void initGui() {
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setResizable(false);
    
          mainMenu = new MainMenu(this);
          playMenu = new Play(this);
    
          contentPanel.add(mainMenu, MENU_ID);
          contentPanel.add(playMenu, PLAY_ID);
    
          frame.add(contentPanel, BorderLayout.CENTER);
    
          frame.pack();
          frame.setVisible(true);
    
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                new BattleShipSwap();
             }
          });
       }
    
       public void switchCard(String id) {
          // contentPanel.setLayout(new CardLayout());
          // CardLayout cardlayout = (CardLayout) contentPanel.getLayout();
    
          // why not just use the field?
          cl.show(contentPanel, id);
       }
    }
    
    class MainMenu extends JPanel {
       private BattleShipSwap battleShipSwap;
    
       public MainMenu(BattleShipSwap battleShipSwap) {
          setBorder(BorderFactory.createTitledBorder("Main Menu"));
          this.battleShipSwap = battleShipSwap;
    
          add(new JButton(new SwapButtonAction(battleShipSwap, BattleShipSwap.PLAY_ID)));
       }
    
    }
    
    class Play extends JPanel {
       private BattleShipSwap battleShipSwap;
    
       public Play(BattleShipSwap battleShipSwap) {
          setBorder(BorderFactory.createTitledBorder("Play Menu"));
          this.battleShipSwap = battleShipSwap;
    
          add(new JButton(new SwapButtonAction(battleShipSwap, BattleShipSwap.MENU_ID)));
       }
    }
    
    class SwapButtonAction extends AbstractAction {
       private BattleShipSwap battleShipSwap;
       private String id;
    
       public SwapButtonAction(BattleShipSwap battleShipSwap, String id) {
          super("Swap");
          putValue(MNEMONIC_KEY, KeyEvent.VK_S);
          this.battleShipSwap = battleShipSwap;
          this.id = id;
       }
    
       @Override
       public void actionPerformed(ActionEvent arg0) {
          battleShipSwap.switchCard(id);
       }
    }
    

    In the future, you'll want to create a minimal compilable and runnable example program, similar to my program above, which demonstrates your problem, an MCVE