如何从另一个 Class 更改 JPanel?

How can I change the JPanel from another Class?

嗨,我是 Java 的新手,我遇到了以下问题:

我创建了一个 JFrame,我希望 JPanel 在单击 JButton 时发生变化。那几乎work.The唯一的问题是程序创建了一个新的window然后有两个windows。一个使用第一个 JPanel,一个使用第二个 JPanel。 这是我当前的代码:

先class:

public class Program {

    public static void main (String [] args) {

        new window(new panel1());

    }
}

秒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);

    }
}

第三个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);

    }
}

第四个class:

public class Panel2 extends JPanel {

    private static final long serialVersionUID = 1L;

    Panel2() {

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

        add(text);

    }
}

但我只想更改 JPanel 而无需打开新的 window。有办法吗?

提前致谢!

首先,看看 Java naming conventions,特别是你的 class 名字应该以大写字母开头。

如果你想避免每次点击按钮时都打开一个新的 window ,你可以将你的框架对象传递给 Panel1 构造函数,并在你点击时设置一个新的 Panel2 实例作为框架内容窗格按钮。也不需要将 Panel1 传递给 Window 构造函数(请注意 Window class 已经在 java.awt 包中定义,最好避免可能的名称冲突重命名您的 class 应用程序Window、我的Window 或其他名称)。

您可以这样更改您的代码(仅相关部分):

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 ());
            }
        };
        // ...
}

另请注意 SwingUtilities 的 invokeLater 调用,这是在 EDT 上下文中初始化 GUI 的最佳方式(有关详细信息,请参阅 this question)。

最后,您可以避免每次单击按钮时都创建一个新的 Panel2 实例,只需使用 CardLayout。 看看official tutorial

这是一个演示

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);
    }
}

这是一个旧问题 post,但以简化的方式回答它可能会有用。感谢mcwolf先生的第一个回答

如果我们想让 1 个子 jframe 与主 jframe 交互以修改其内容,让我们考虑以下情况。 parent.javachild.java。 所以,在 parent.java 中,我们有这样的东西:

Parent.java

public class Parent extends JFrame implements ActionListener{
    //attributes
    //here is the class we want to modify
    private some_class_to_modify = new some_class_to_modify();
    //here is a container which contains the class to modify
    private JPanel container = new JPanel();
    private some_class = new some_class();
    private int select;
    //....etc..etc
    //constructor
    public Parent(){
        this.setTitle("My title");
        //etc etc
        
        //etc....etc
        container.add(some_class_to_modify,borderLayout.CENTER);
    }
    //I use for instance actionlisteners on buttons to trigger the new JFrame
    public void actionPerformed(ActionEvent arg0){  
        if((arg0.getSource() == source_button_here)){
            //Here we call the child class and send the parent's attributes with "this"
            Child child = new Child(this);
        }
        //... all other cases
    }//Here is the class where we want to be able to modify our JFrame. Here ist a JPanel (Setcolor)
    public void child_action_on_parent(int selection){
        this.select = selection;
        System.out.println("Selection is: "+cir_select);
        if(select == 0) {
            //Do $omething with our class to modify
            some_class_to_modify.setcolor(Color.yellow);
        }
        
    }

child.java中,我们会有这样的东西:

public class Child extends JFrame implements ActionListener {
    //Again some attributes here
    private blabla;
    //Import Parent JFrame class
    private Parent owner;
    private int select_obj=0;
    //Constructor here and via Parent Object Import
    public Child(Parent owner){
      /*By calling the super() method in the constructor method, we call the parent's 
      constructor method and gets access to the parent's properties and methods:*/
        super();
        this.owner = owner;
        this.setTitle("Select Method");
        this.setSize(400, 400);
        this.setContentPane(container);
        this.setVisible(true);
      }
    
    class OK_Button  implements ActionListener {
        public void actionPerformed(ActionEvent e) {     
                
                Object Selection = select;
                if(Selection == something) {
                    select_obj=0;
                    valid = JOptionPane.showConfirmDialog(null,"You have chosen option 1. Do you want to continue?","Minimum diameter",2);
                }
                System.out.println("Option is:"+valid);
                if(valid == 0) {
                    setVisible(false);
                    //Here we can use our herited object to call the child_action_on_parent public class of the Parent JFrame. So it can modify directly the Panel
                    owner.child_action_on_parent(select_obj);
                }
            }
    }