views:

678

answers:

5

G'day all,

I am coding a main menu for a project. The menu displays properly. I have also set up ActionListeners for the three buttons on the menu.

What I wish to do is reuse the JPanel for a new set of radio buttons when the user chooses "Start a New Game".

However, coding ActionPerformed to remove the existing components from the JPanel has me stumped. I know removeAll is somehow important, but unfortunately NetBeans informs me I cannot call it on my mainMenu JPanel object within ActionPerformed. So i have commented it out in my code below, but left it in so you can see what I am trying to do.

Your thoughts or hints are appreciated.

Here is my main code:

public class Main {

    public static void main(String[] args) {
        MainMenu menu = new MainMenu();
        menu.pack();
        menu.setVisible(true);
    }
}

Here is my mainMenu code:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

    public class MainMenu extends JFrame implements ActionListener {
        JButton startNewGame = new JButton("Start a New Game");
        JButton loadOldGame = new JButton("Load an Old Game");
        JButton seeInstructions = new JButton("Instructions");

        public MainMenu() {
            super("RPG Main Menu");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JPanel mainMenu = new JPanel();
            mainMenu.setLayout(new FlowLayout());
            startNewGame.setMnemonic('n');
            loadOldGame.setMnemonic('l');
            seeInstructions.setMnemonic('i');
            startNewGame.addActionListener(this);
            loadOldGame.addActionListener(this);
            seeInstructions.addActionListener(this);
            mainMenu.add(startNewGame);
            mainMenu.add(loadOldGame);
            mainMenu.add(seeInstructions);
            setContentPane(mainMenu);

        }

        public void actionPerformed(ActionEvent evt) {
            Object source = evt.getSource();
            if (source == startNewGame) {
                // StartNewGame code goes here
                // mainMenu.removeAll();
            }
            if (source == loadOldGame) {
                // LoadOldGame code goes here
            }
            if (source == seeInstructions) {
                // Quit code goes here
            }
        }
    }
+1  A: 

You don't have a reference to mainMenu actionPerformed use. If you declare mainMenu with the buttons. It would work.

Clint
+1  A: 

You need mainMenu to be a member variable:

 public class MainMenu extends JFrame implements ActionListener {
        JButton startNewGame = new JButton("Start a New Game");
        JButton loadOldGame = new JButton("Load an Old Game");
        JButton seeInstructions = new JButton("Instructions");
        JPanel mainMenu = new JPanel();

Why do you feel the need to re-use this object?

Tom
A: 

The problem is that the actionPerformed method is trying to call the JPanel mainMenu which is out of scope, i.e. the mainMenu variable is not visible from the actionPerformed method.

One way to get around this is to have the JPanel mainMenu declaration in the class itself and make it an instance field which is accessible to all instance methods of the class.

For example:

public class MainMenu extends JFrame implements ActionListener
{
    ...
    JPanel mainMenu;

    public MainMenu()
    {
        ...
        mainMenu = new JPanel();
        ...
    }

    public void actionPerformed(ActionEvent e)
    {
        ...
        mainMenu.removeAll();
    }
}
coobird
+2  A: 

Consider using a CardLayout instead, which manages two or more components (usually JPanel instances) that share the same display space. That way you don't have to fiddle with adding and removing components at runtime.

Zach Scrivena
Thanks Zach. I will consider CardLayout.
elwynn
A: 

Avoid attempting to "reuse" stuff. Computers are quite capable of tidying up. Concentrate on making you code clear.

So instead of attempting to tidy up the panel, simply replace it with a new one.

Generally a better way to write listeners is as anonymous inner classes. Code within these will have access to final variables in the enclosing scope and to members of the enclosing class. So, if you make mainMenu final and you ActionListeners anonymous inner classes, your code should at least compile.

Also don't attempt to "reuse" classes. Try to make each class do one sensible thing, and avoid inheritance (of implementation). There is almost never any need to extend JFrame, so don't do that. Create an ActionListener for each action, rather than attempting to determine the event source.

Also note, you should always use Swing components on the AWT Event Dispatch Thread. Change the main method to add boilerplate something like:

public static void main(final String[] args) {
    java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
        runEDT();
    }});
}
Tom Hawtin - tackline