How can I change the JPanel from another Class?

2019-08-21 03:10发布

问题:

Hi, I'm new to Java and I have the following problem:

I created a JFrame and I want the JPanel to change when clicking a JButton. That does almost work.The only problem is that the program creates a new window and then there are two windows. One with the first JPanel and one with the second JPanel. Here is my current code:

first class:

public class Program {

    public static void main (String [] args) {

        new window(new panel1());

    }
}

second class:

import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Window extends JFrame {

    private static final long serialVersionUID = 1L;

    Window(JPanel panel) {

        setLocation((int) Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 200,
                    (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 100);
        setSize(400, 200);
        setTitle("test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        setContentPane(panel);
        setVisible(true);

    }
}

third class:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;

public class Panel1 extends JPanel {

    private final long serialVersionUID = 1L;

    Panel1() {

        JButton nextPanelButton = new JButton("click here");

        add(nextPanelButton);

        ActionListener changePanel = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                new window(new panel2());
            }
        };
        nextPanelButton.addActionListener(changePanel);

    }
}

fourth class:

public class Panel2 extends JPanel {

    private static final long serialVersionUID = 1L;

    Panel2() {

        JLabel text = new JLabel("You pressed the Button!");

        add(text);

    }
}

But I just want to change the JPanel without opening a new window. Is there a way to do that?

Thanks in advance!

回答1:

This is a demo

import javax.swing.*;

public class Main {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new MainFrame("Title").setVisible(true);
        });
    }
}

MainFrame.java

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

public class MainFrame extends JFrame {
    private JPanel viewPanel;

    public MainFrame(String title) {
        super(title);
        createGUI();
    }

    private void createGUI() {
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setLayout(new BorderLayout());
        setMinimumSize(new Dimension(600, 480));

        viewPanel = new JPanel(new BorderLayout());
        add(viewPanel, BorderLayout.CENTER);

        showView(new View1(this));
        pack();
   }

   public void showView(JPanel panel) {
        viewPanel.removeAll();
        viewPanel.add(panel, BorderLayout.CENTER);
        viewPanel.revalidate();
        viewPanel.repaint();
   }
}

View1.java

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

public class View1 extends JPanel {
    final private MainFrame owner;

    public View1(MainFrame owner) {
        super();

        this.owner = owner;
        createGUI();
    }

    private void createGUI() {
        setLayout(new FlowLayout());
        add(new JLabel("View 1"));

        JButton button = new JButton("Show View 2");
        button.addActionListener(event -> {
            SwingUtilities.invokeLater(() -> owner.showView(new View2(owner)));
        });

        add(button);
    }
}

View2.java

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

public class View2 extends JPanel {
    final private MainFrame owner;

    public View2(MainFrame owner) {
        super();

        this.owner = owner;
        createGUI();
    }

    private void createGUI() {
        setLayout(new FlowLayout());
        add(new JLabel("View 2"));

        JButton button = new JButton("Show View 1");
        button.addActionListener(event -> {
            SwingUtilities.invokeLater(() -> owner.showView(new View1(owner)));

        });

        add(button);
    }
}


回答2:

First of all, take a look at Java naming conventions, in particular your class names should start with a capitalized letter.

If you want to avoid to open a new window every time you click the button, you could pass your frame object to Panel1 constructor, and setting a new Panel2 instance as the frame content pane when you click the button. There is also no need to pass Panel1 to Window constructor (please note that Window class is already defined in java.awt package, it would be better to avoid a possible name clash renaming your class ApplicationWindow, MyWindow or something else).

You could change your code like this (only relevant parts):

public class Program
{
    public static void main (String [] args) {
        SwingUtilities.invokeLater (new Runnable () {
            @Override public void run () {
                new Window ().setVisible (true);
            }
        };
    }
}
class Window extends JFrame
{
    // ...

    Window () {
        // ...
        setContentPane(new Panel1 (this));
    }
}
class Panel1 extends JPanel
{
    // ...

    Panel1 (JFrame parent) {
        // ...
        ActionListener changePanel = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                parent.setContentPane (new Panel2 ());
            }
        };
        // ...
}

Also note the SwingUtilities's invokeLater call, which is the best way to initialise your GUI in the EDT context (for more info look at this question).

Finally, you could avoid to create a new Panel2 instance every time you click the button, simply by using a CardLayout. Take a look at the official tutorial.