Search code examples
javaswingjframeruntime-errorcontentpane

Neither setContentPane() nor getContentPane().add() works


I can provide all of my code if that would aid in the problem, but I believe since this only affects one class really, it can be solved here, to simplify the issue.

I have a solitaire project (mind the package/class name, it was trial and error and I didn't delete the old projects) that refuses to accept the GameArea class I have, which extends JPanel. The GameArea works fine in its own separate instance where the tester class runs with only the JPanel on the JFrame. That tester class uses setContentPane(newGame) to add it to the JFrame.

In the class below, neither getContentPane().add(newGame) nor setContentPane(newGame) successfully adds the game to the frame. This class sets up a main menu, with two buttons. The first one takes it into the Start New Game screen, and then the button which is supposed to start the game will either:

1) show only a green screen if getContentPane().add(newGame) is used

2) show a pressed Start New Game, and then freeze on the Start New Game screen if setContentPane(newGame) is used. This is frustrating because getContentPane().removeAll() is called before this...However, using the menu, I can return to the main menu and still run in that infinite loop of freeze and fix.

I suspect because I don't know enough about swing classes yet that I'm missing something. Any help is greatly appreciated, since I need to have this done in 2 days.

package guitestersolitairenew;
/**
 *
 * @author Josh
 * @version 1.00 2015/3/28
 */
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import static javax.swing.Action.MNEMONIC_KEY;
import static javax.swing.Action.SHORT_DESCRIPTION;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.GroupLayout;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class GUITesterSolitaireNew extends JFrame 
{

    public GUITesterSolitaireNew() 
    {
        initComponents();
        setMainMenu();
    }

    private void initComponents() 
    {
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setBackground(new java.awt.Color(80, 135, 40));
        setTitle("Klondike Solitaire");
        getContentPane().setBackground(new java.awt.Color(85,130,40));
        setSize(1200,700);
        setLocationRelativeTo(null);
        setResizable(false);

        JMenuBar menubar = new JMenuBar();
        menubar.add(new JMenu("File"));

        class MainMenu extends AbstractAction
        {
            public MainMenu(String text, ImageIcon icon, String desc, Integer mnemonic)
            {
                super(text,icon);
                putValue(SHORT_DESCRIPTION, desc);
                putValue(MNEMONIC_KEY, mnemonic);
            }

            @Override
            public void actionPerformed(ActionEvent e)
            {
                setMainMenu();
            }
        }
        menubar.getMenu(0).add(new JMenuItem(new MainMenu("Main Menu", null, "Return to the main menu.", KeyEvent.VK_M)));

    class NewGame extends AbstractAction
    {
        public NewGame(String text, ImageIcon icon, String desc, Integer mnemonic)
        {
            super(text,icon);
            putValue(SHORT_DESCRIPTION, desc);
                    putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e)
        {
                    newGame(e);
        }
    }
        menubar.getMenu(0).add(new JMenuItem(new NewGame("New Game", null, "Start a new game.", KeyEvent.VK_N)));

    class RestartGame extends AbstractAction
    {
        public RestartGame(String text, ImageIcon icon, String desc, Integer mnemonic)
        {
            super(text,icon);
            putValue(SHORT_DESCRIPTION, desc);
                    putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e)
        {
            //Fix to restart game.
        }
    }
        menubar.getMenu(0)
                .add(new JMenuItem(new RestartGame("Restart Game", null, "Restart the current game.", KeyEvent.VK_R)));

    class LoadGame extends AbstractAction
    {
        public LoadGame(String text, ImageIcon icon, String desc, Integer mnemonic)
        {
            super(text,icon);
            putValue(SHORT_DESCRIPTION, desc);
                    putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e)
        {
            //Fix to load game.
        }
    }
        menubar.getMenu(0).add(new JMenuItem(new LoadGame("Load Game", null, "Load a saved game.", KeyEvent.VK_L)));

        class SaveGame extends AbstractAction
        {
            public SaveGame(String text, ImageIcon icon, String desc, Integer mnemonic)
            {
                super(text,icon);
                putValue(SHORT_DESCRIPTION, desc);
                putValue(MNEMONIC_KEY, mnemonic);
            }

            @Override
            public void actionPerformed(ActionEvent e)
            {
                //Fix to save game
            }
        }
        menubar.getMenu(0).add(new JMenuItem(new SaveGame("Save Game", null, "Create a save file.", KeyEvent.VK_S)));

        class ExitAction extends AbstractAction
        {
        public ExitAction (String text, ImageIcon icon, String desc, Integer mnemonic)
        {
                super(text, icon);
                putValue(SHORT_DESCRIPTION, desc);
                putValue(MNEMONIC_KEY, mnemonic);
            }

            @Override
            public void actionPerformed(ActionEvent e) 
            {
                System.exit(0);
            }
        }
        menubar.getMenu(0).add(new JMenuItem(new ExitAction("Exit", null, "Exit from the program.", KeyEvent.VK_E)));


        menubar.add(new JMenu("Help"));

        class Rules extends AbstractAction
        {
        public Rules (String text, ImageIcon icon, String desc, Integer mnemonic)
        {
                super(text, icon);
                putValue(SHORT_DESCRIPTION, desc);
                putValue(MNEMONIC_KEY, mnemonic);
            }

            @Override
            public void actionPerformed(ActionEvent e) 
            {
                JFrame rules = new JFrame("Klondike Solitaire Rules");
                rules.setSize(400,430);
                rules.setLocationRelativeTo(null);
                rules.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

                JTextArea jta = new JTextArea();
                jta.setEditable(false);
                Component add = rules.add(jta);
                JScrollPane jsp = new JScrollPane();
        jsp.setViewportView(jta); 
        rules.getContentPane().add(jsp, java.awt.BorderLayout.CENTER); 
        jta.setCaretPosition(jta.getText().length());

                jta.append("Klondike Solitaire Rules:\n\n");
                jta.setCaretPosition(jta.getText().length());

                jta.append("The game starts with a standard 52 card deck.\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("The cards are first dealt into 7 'tableaus' where the cards\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("are all turned face down and one card laid onto each tableau.\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("The left one is turned up, and the process is repeated for the\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("2nd to 7th tableaus. The 2nd card in the 2nd tableau is turned up.\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("Each tableau receives as many cards as the column position. The\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("last card in each tableau will be face up. The deck is placed\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("off to the side.\n\n");
                jta.setCaretPosition(jta.getText().length());

                jta.append("The cards are drawn one at a time from deck. Valid moves are: \n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("-Move card from deck to tableau\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("-Move card from deck to foundation <stacks by suit>\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("-Click deck again for another card.\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("The deck is cycled if cards are remaining. The cards, after\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("being face up, will sort in descent of value and opposing\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("face color: i.e. a black 6 can only go on top of a red 7.\n\n");
                jta.setCaretPosition(jta.getText().length());

                jta.append("The player wins by moving all cards from the deck and tableaus\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("to the 4 foundations. The foundations sort by suit in ascending\n");
                jta.setCaretPosition(jta.getText().length());
                jta.append("order of value, starting with the ace. All aces are low.");

                rules.setResizable(false);
        rules.setVisible(true);
            }
        }
        menubar.getMenu(1)
                .add(new JMenuItem(new Rules("Rules", null, "Show a popup aid for the rules of the game.", KeyEvent.VK_R)));

    class Info extends AbstractAction
        {
        public Info (String text, ImageIcon icon, String desc, Integer mnemonic)
        {
                super(text, icon);
                putValue(SHORT_DESCRIPTION, desc);
                putValue(MNEMONIC_KEY, mnemonic);
            }

            @Override
            public void actionPerformed(ActionEvent e) 
            {
                JFrame info = new JFrame("Development Info");
        info.setSize(450,225);
                info.setLocationRelativeTo(null); //sends it to center of screen
        info.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); //does not close application, but actually kills the window when closed
        JTextArea jta = new JTextArea();
                jta.setEditable(false); //The user can't type on the text box.
            Component add = info.add(jta); //abstraction that adds the component jta to window info
            JScrollPane jsp = new JScrollPane();

        jsp.setViewportView(jta); //puts the text area in the scroll pane
        info.getContentPane().add(jsp, java.awt.BorderLayout.CENTER); //centers the text area and scroll pane to be the main subject of the frame
        jta.setCaretPosition(jta.getText().length()); //sets the cursor to the end of the text typed so far

        //edited out

                info.setResizable(false);
        info.setVisible(true);
            }
        }
        menubar.getMenu(1)
                .add(new JMenuItem(new Info("Info", null, "Information about Klondike Solitaire.", KeyEvent.VK_I)));
        setJMenuBar(menubar);

    }                        

    private void newGame(java.awt.event.ActionEvent evt) 
    {                                         
        getContentPane().removeAll();
        getContentPane().repaint();
        setBackground(new java.awt.Color(80, 135, 40));

        JLabel jLabel1 = new JLabel();
        JButton jButton1 = new JButton();

        jLabel1.setBackground(new java.awt.Color(80, 135, 40));
        jLabel1.setFont(new java.awt.Font("Kunstler Script", 1, 120)); // NOI18N
        jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel1.setText("Klondike Solitaire");
        jLabel1.setVerticalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel1.setMaximumSize(new java.awt.Dimension(800, 100));
        jLabel1.setMinimumSize(new java.awt.Dimension(800, 100));
        jLabel1.setPreferredSize(new java.awt.Dimension(800, 100));
        jLabel1.setRequestFocusEnabled(true);

        jButton1.setText("Start New Game");
        jButton1.setFont(new java.awt.Font("Times New Roman", 1, 20));
        jButton1.setMaximumSize(new java.awt.Dimension(200, 50));
        jButton1.setMinimumSize(new java.awt.Dimension(200, 50));
        jButton1.setPreferredSize(new java.awt.Dimension(200, 50));
        jButton1.addActionListener(new java.awt.event.ActionListener() 
        {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) 
            {
                startNewGame();
            }
        });

        JLabel replay = new JLabel("Replay game from seed:");
        replay.setBackground(new java.awt.Color(80,135,40));
        replay.setFont(new java.awt.Font("Times New Roman", 1, 20));
        replay.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        replay.setVerticalAlignment(javax.swing.SwingConstants.CENTER);
        replay.setMaximumSize(new java.awt.Dimension(220, 50));
        replay.setMinimumSize(new java.awt.Dimension(220, 50));
        replay.setPreferredSize(new java.awt.Dimension(220, 50));

        JTextField getSeed = new JTextField();
        getSeed.setCaretPosition(getSeed.getText().length());
        getSeed.setFont(new java.awt.Font("Times New Roman", 1, 18));
        getSeed.setMaximumSize(new java.awt.Dimension(150, 24));
        getSeed.setMinimumSize(new java.awt.Dimension(150, 24));
        getSeed.setPreferredSize(new java.awt.Dimension(150, 24));

        JButton startSeed = new JButton("Start Game");
        startSeed.setFont(new java.awt.Font("Times New Roman", 1, 20));
        startSeed.setMaximumSize(new java.awt.Dimension(130, 30));
        startSeed.setMinimumSize(new java.awt.Dimension(130, 30));
        startSeed.setPreferredSize(new java.awt.Dimension(130, 30));
        startSeed.addActionListener(new java.awt.event.ActionListener()
        {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                startNewGame(Integer.parseInt(getSeed.getText()));
            }
        });

        JButton back = new JButton("Back to Main Menu");
        back.setFont(new java.awt.Font("Times New Roman", 1, 20));
        back.setMaximumSize(new java.awt.Dimension(200, 50));
        back.setMinimumSize(new java.awt.Dimension(200, 50));
        back.setPreferredSize(new java.awt.Dimension(200, 50));
        back.addActionListener(new java.awt.event.ActionListener()
        {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                setMainMenu();
            }
        });

        GroupLayout layout = new GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.CENTER)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(200, 200, 200)
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER, false)
                            .addComponent(back, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(replay, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(getSeed, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(startSeed, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                            .addComponent(jButton1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                        .addGroup(layout.createSequentialGroup()
                        .addGap(200, 200, 200)
                        .addComponent(jLabel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(90, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(150, 150, 150)
                .addComponent(jLabel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addGap(10, 10, 10)
                .addComponent(jButton1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addGap(35, 35, 35)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER)
                    .addComponent(replay, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(getSeed, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(startSeed, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGap(180, 180, 180)
                .addComponent(back, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
        );

    } 

    private void startNewGame() 
    {
        getContentPane().removeAll();
        getContentPane().repaint();

        newGame.newGame();
        Container pane = getContentPane();
        pane.add(newGame);
        setContentPane(pane);
        getContentPane().revalidate();
        getContentPane().repaint();
    }

    public void startNewGame(int seed)
    {
        getContentPane().removeAll();
        getContentPane().repaint();

        newGame.newGame();
        add(newGame);
    }

    private void setMainMenu()
    {
        getContentPane().removeAll();
        getContentPane().repaint();
        setBackground(new java.awt.Color(80, 135, 40));

        JLabel jLabel1 = new javax.swing.JLabel();
        JButton jButton1 = new javax.swing.JButton();
        JButton jButton2 = new javax.swing.JButton();

        jLabel1.setBackground(new java.awt.Color(80, 135, 40));
        jLabel1.setFont(new java.awt.Font("Kunstler Script", 1, 120)); // NOI18N
        jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel1.setText("Klondike Solitaire");
        jLabel1.setVerticalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel1.setMaximumSize(new java.awt.Dimension(800, 100));
        jLabel1.setMinimumSize(new java.awt.Dimension(800, 100));
        jLabel1.setPreferredSize(new java.awt.Dimension(800, 100));
        jLabel1.setRequestFocusEnabled(true);

        jButton1.setText("New Game");
        jButton1.setFont(new java.awt.Font("Times New Roman", 1, 20));
        jButton1.setMaximumSize(new java.awt.Dimension(200, 50));
        jButton1.setMinimumSize(new java.awt.Dimension(200, 50));
        jButton1.setPreferredSize(new java.awt.Dimension(200, 50));
        jButton1.addActionListener(new java.awt.event.ActionListener() 
        {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) 
            {
                newGame(evt);
            }
        });

        jButton2.setText("Load Game");
        jButton2.setFont(new java.awt.Font("Times New Roman", 1, 20));
        jButton2.setMaximumSize(new java.awt.Dimension(200, 50));
        jButton2.setMinimumSize(new java.awt.Dimension(200, 50));
        jButton2.setPreferredSize(new java.awt.Dimension(200, 50));

        GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.CENTER)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(200, 200, 200)
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER, false)
                            .addComponent(jButton2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(jButton1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(200, 200, 200)
                        .addComponent(jLabel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(90, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(150, 150, 150)
                .addComponent(jLabel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addGap(10, 10, 10)
                .addComponent(jButton1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addGap(5, 5, 5)
                .addComponent(jButton2)
                .addContainerGap(120, Short.MAX_VALUE))
        );
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) 
    {
        /* Set the Nimbus look and feel */
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try 
        {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) 
            {
                System.out.println("Main.main(): 492");
                if ("Nimbus".equals(info.getName())) 
                {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } 
        catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) 
        {
            java.util.logging.Logger.getLogger(GUITesterSolitaireNew.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() 
        {
            @Override
            public void run() 
            {
                new GUITesterSolitaireNew().setVisible(true);
            }
        });
    }

    private javax.swing.JInternalFrame jInternalFrame1;
    private GameArea newGame = new GameArea();
}

Solution

  • Don't use setContentPane to switch views, use a CardLayout, that's what it's designed for. See How to Use CardLayout for more details

    Also, there's little point to doing this...

    setContentPane(pane);
    getContentPane().revalidate();
    getContentPane().repaint();
    

    In this instance, it's not the contentPane that needs to be revalidated, it's the contentPanes parent...