How to create new and dispose jcomponents multiple times?

712 views Asked by At

(Sorry if this question is not done properly, I'm new. But at least I researched a lot before asking my own question)

Hello. I'm writing a blackjack game in java and it's turning quite massive. My problem is how to handle multiple instances of swing components, I guess you can call it. I can't figure out wether to create the components (such as jpanels and jbuttons) as class level, or in specific methods.

If I create them in their corresponding method, then my action listener can't see them, but if I create them as class level, then they get deleted when I call dispose().

 class BlackjackGame extends JFrame implements ActionListener{

    public void mainMenu(){

        JPanel menuPane = new JPanel(new GridBagLayout()); //Init of main menu
        GridBagConstraints c = new GridBagConstraints();
        menuPane.setBackground(new Color(125,0,0));
        menuPane.setBounds(620,220,175,250);

        JLabel menuTitle = new JLabel("Welcome to Blackjack!");//Main menu-content
        c.gridx = 1;
        c.gridy = 0;
        c.insets = new Insets(0,0,20,0);
        menuPane.add(menuTitle, c);

        JButton playButton = new JButton("Play!");
        playButton.addActionListener(this);
        c.gridx = 0;
        c.gridy = 1;
        c.gridwidth = 3;
        c.ipadx = 25;
        c.ipady = 25;
        c.insets = new Insets(0,0,0,0);
        menuPane.add(playButton, c);

        JButton exitButton = new JButton("Exit!");
        exitButton.addActionListener(this);
        c.gridx = 0;
        c.gridy = 2;
        c.gridwidth = 3;
        menuPane.add(exitButton, c);

        JButton rulesButton = new JButton("Set rules.");
        rulesButton.addActionListener(this);
        c.gridx = 0;
        c.gridy = 3;
        c.gridwidth = 3;
        menuPane.add(rulesButton, c);

        this.add(menuPane,0);
    }

    //This is where I get problems
    public void actionPerformed (ActionEvent event){
        if(event.getSource() == playButton){
            //I want the menuPane to disappear, and a transition into the game.
            menuPane.dispose();
            //Call method for the rest of the game.

        }else if(event .getSource() etcetera etcetera){
            etcetera etcetera
        }
    }
}

When done this way, the actionlistener cannot find my components, such as playButton or menuPane. But if I had introduced them as class level objects:

class BlackjackGame extends JFrame implements ActionListener{

    JPanel menuPane = new JPanel(new GridBagLayout());
    JLabel menuTitle = new JLabel("Welcome to Blackjack!");
    JButton playButton = new JButton("Play!");
    JButton exitButton = new JButton("Exit!");
    JButton rulesButton = new JButton("Set rules.");

    public void mainMenu(){
        //Rest of code
    }

    public void actionPerformed(ActionEvent event){
        menuPane.dispose();
        //Rest of code
    }
}

...then as I call menuPane.dispose(), how can I get it back when I want to call mainMenu() again? If I want to go back to the main menu, then I would need to create a new instance of menuPane, as well as all the buttons, but as they are class level and already disposed I can't.

Please help me, and thank you!

PS. I can post my full code as it is atm if it would help.

Edit: Dan's answer has been accepted, as it was indeed the correct answer and it worked for my specific program very well. Thank you and merry christmas!

1

There are 1 answers

6
Dan On BEST ANSWER

First, unless I've misunderstood your code, menuPane.dispose() shouldn't work as JPanel does not have a function called dispose()

The best way to do what you want to do if you want to use the same menuPane for the menu. Instead of menuPane.dispose(); use remove(menuPane); and then add(yourOtherPanel);

Working Example

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class BlackjackGame extends JFrame implements ActionListener {
    private JPanel menuPane;
    private JLabel menuTitle;
    private JButton playButton;
    private JButton exitButton;
    private JButton rulesButton;

    private JPanel otherPane;
    private JLabel otherTitle;
    private JButton otherButton;

    public BlackjackGame() {
        mainMenu();
        otherPanel();
        setSize(400, 400);
        setVisible(true);
    }

    private void mainMenu() {

        menuPane = new JPanel(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        menuPane.setBackground(new Color(125,0,0));
        menuPane.setBounds(620,220,175,250);

        menuTitle = new JLabel("Welcome to Blackjack!");
        c.gridx = 1;
        c.gridy = 0;
        c.insets = new Insets(0,0,20,0);
        menuPane.add(menuTitle, c);

        playButton = new JButton("Play!");
        playButton.addActionListener(this);
        c.gridx = 0;
        c.gridy = 1;
        c.gridwidth = 3;
        c.ipadx = 25;
        c.ipady = 25;
        c.insets = new Insets(0,0,0,0);
        menuPane.add(playButton, c);

        exitButton = new JButton("Exit!");
        exitButton.addActionListener(this);
        c.gridx = 0;
        c.gridy = 2;
        c.gridwidth = 3;
        menuPane.add(exitButton, c);

        rulesButton = new JButton("Set rules.");
        rulesButton.addActionListener(this);
        c.gridx = 0;
        c.gridy = 3;
        c.gridwidth = 3;
        menuPane.add(rulesButton, c);

        add(menuPane);
    }

    private void otherPanel() {
        otherPane = new JPanel(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        otherPane.setBackground(new Color(125,0,0));
        otherPane.setBounds(620,220,175,250);

        otherTitle = new JLabel("Welcome to Second Pane!");
        c.gridx = 1;
        c.gridy = 0;
        c.insets = new Insets(0,0,20,0);
        otherPane.add(otherTitle, c);

        otherButton = new JButton("Go Back!");
        otherButton.addActionListener(this);
        c.gridx = 0;
        c.gridy = 1;
        c.gridwidth = 3;
        c.ipadx = 25;
        c.ipady = 25;
        c.insets = new Insets(0,0,0,0);
        otherPane.add(otherButton, c);
    }

    public void actionPerformed (ActionEvent event) {
        if(event.getSource() == playButton) {
            remove(menuPane);
            add(otherPane);
            validate();
            repaint();

        } else if(event.getSource() == otherButton) {
            remove(otherPane);
            add(menuPane);
            validate();
            repaint();
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> new BlackjackGame());
    }
}

Edit for comments

So the java method remove() only removes the object from the container, which in this case is the JFrame. This method does not effect the object it moves so the object can be reused later. Hence why in the code above I can just use the remove() and add() methods without redeclaring or remaking menuPane and otherPane.

As for why I declare the objects like this

`private JPanel menuPane;`

And then initialize like this

menuPane = new JPanel(new GridBagLayout());

This is because I want the ActionListener to be able to see the objects without initializing them straight away. The line private JPanel menuPane; makes the object a global variable and the line menuPane = new JPanel(new GridBagLayout()); makes it into what I am going to use. Doing it this way instead of JPanel menuPane = new JPanel(new GridBagLayout()); also means I can reuse the same variable in multiple methods. For example

private JPanel panel;

private void createPanelOne() {
    panel = new JPanel(new FlowLayout());
    ...
    add(panel);
}

private void createPanelTwo() {
    panel = new JPanel(new GridBagLayout());
    ...
    add(panel);
}

After doing this, you will have two JPanels in your JFrame and they will be different, but you only need to use one JPanel

This is the other way of declaring it and it makes a local variable. Local variables aren't visible to other methods outside of the method you are using unless you pass them through.

JPanel panel = new JPanel();

I wouldn't say this is a con in the slightest. I think sometimes it is good to use local variables in a method that shouldn't be visible to other methods.

Finally to pass local variables through to other methods you can use arguments in a method you have made. For example

public void setSomeValue(int val) {
    someValue = val;
}