如何通过单击JButton添加JPanel?

我正在尝试创建一个小的GUI,它有2个JButton和2个JPanel,每个都有一些绘图动画。 默认情况下,它必须显示第一个JPanel,并通过单击第二个JButton我想看到我的第二个JPanel。 所以:我创建了JFrame,Panel1和Panel2,在那里我绘制了我的动画,创建了Button1和Button2并添加了ActionListeners。 我还有MainPanel,它有一个字段变量i。 通过更改此“i”我的构造函数将MainPanel添加到Panel1(默认)或Panel2(通过单击JButton2我更改i)。 比我把这个MainPanel添加到我的框架。 所以我的问题:在类MainPanel中我有refreshMe方法,我应该在那里写什么才能让我的GUI正常工作? 谢谢。 这是我的代码:

import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class GuiTest { public static void main(String[] args) { JFrame f = new JFrame(); MainPanel myPanel = new MainPanel(); f.add(myPanel); Button1 button1 = new Button1(); Button2 button2 = new Button2(); myPanel.add(button1); myPanel.add(button2); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); f.setVisible(true); } } class MainPanel extends JPanel { Panel1 p1 = new Panel1(); Panel2 p2 = new Panel2(); public int i = 1; //this is being changed later by clicking JButton // I use this setter later in actionPerformed in order to change i public void setI(int i) { this.i = i; } MainPanel() { if (i == 1) { this.add(p1); } if (i == 2) { this.add(p2); } } public void refreshMe() { // Need some help here: // I don't know what should I write, how to make a repaint of myPanel? System.out.println("just test, if the method refreshMe working by clicking some button"); } } class Panel1 extends JPanel { public Panel1() { this.setBackground(Color.BLUE); // a lot of drawing stuff going on here } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } } class Panel2 extends JPanel { public Panel2() { this.setBackground(Color.GREEN); // a lot of drawing stuff going on here } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } } class Button1 extends JButton { MainPanel someObj1 = new MainPanel(); Button1() { setText("Show Annimation A"); addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { someObj1.setI(1); System.out.println("The variable i is now: " + someObj1.i); someObj1.refreshMe(); } }); } } class Button2 extends JButton { MainPanel someObj2 = new MainPanel(); Button2() { setText("Show Annimation B"); addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { someObj2.setI(2); System.out.println("The variable i is now: " + someObj2.i); someObj2.refreshMe(); } }); } } 

为了在添加/删除或调整可见容器上的组件之后反映更改,在添加/删除或调整组件大小后,在容器实例上调用revalidate()repaint()

虽然这在你的代码中不起作用,但主要的原因是在JButton类中你重新创建一个新的MainPanel实例,而实际上2个MainPanel应该共享正在使用的单个实例(你可以将MainPanel实例传递给JButton的构造函数,但是除非添加自定义function,否则你不应该真正扩展JButton ):

 class Button2 extends JButton { MainPanel someObj2 = new MainPanel();//you create an instance of MainPanel which isnt even showing and than do changes on that, this way you will never see any of the changes Button2() { } } 

关于您的代码的一些其他建议:

  • 不要不必要地扩展JButton类,只需像创建JFrame一样创建一个JButton实例,并在JButton实例上调用方法。

  • 不要忘记在Event Dispatch Thread上创建/操作Swing组件,通过SwingUtilities.invokeLater(..)块, 在此处阅读更多内容。

以下是您修复的代码(以上建议已实施):

 import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class Test { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JFrame f = new JFrame(); final MainPanel myPanel = new MainPanel(); f.add(myPanel); JButton button1 = new JButton("Show Animation A"); JButton button2 = new JButton("Show Animation B"); button1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { myPanel.setI(1); System.out.println("The variable i is now: " + myPanel.i); myPanel.refreshMe(); } }); button2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { myPanel.setI(2); System.out.println("The variable i is now: " + myPanel.i); myPanel.refreshMe(); } }); myPanel.add(button1); myPanel.add(button2); myPanel.checkPanel(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); f.setVisible(true); } }); } } class MainPanel extends JPanel { Panel1 p1 = new Panel1(); Panel2 p2 = new Panel2(); public int i = 1; //this is being changed later by clicking JButton // I use this setter later in actionPerformed in order to change i public void setI(int i) { this.i = i; } public void refreshMe() { checkPanel(); revalidate(); repaint(); // Need some help here: // I don't know what should I write, how to make a repaint of myPanel? System.out.println("just test, if the method refreshMe working by clicking some button"); } public void checkPanel() { if (i == 1) { this.add(p1); this.remove(p2);//or it will remain there as this is default flowlayout } else if (i == 2) { this.add(p2); this.remove(p1); } } } class Panel1 extends JPanel { public Panel1() { this.setBackground(Color.BLUE); // a lot of drawing stuff going on here } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } } class Panel2 extends JPanel { public Panel2() { this.setBackground(Color.GREEN); // a lot of drawing stuff going on here } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } } 

但是,我建议更简单,幸运的是你有两个选择:

1)使用CardLayout ,它允许您在单个JFrame /容器上的多个组件之间进行切换。

这是我做的一个例子:

在此处输入图像描述

 import java.awt.BorderLayout; import java.awt.CardLayout; 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; import javax.swing.SwingUtilities; public class Test { private final static String PANEL1 = "panel 1"; private final static String PANEL2 = "panel 2"; public Test() { initComponents(); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new Test(); } }); } private void initComponents() { JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel1 = new JPanel(); panel1.add(new JLabel("Panel 1")); JPanel panel2 = new JPanel(); panel2.add(new JLabel("Panel 2")); //Create the panel that contains the "cards". final JPanel cards = new JPanel(new CardLayout()); cards.add(panel1, PANEL1); cards.add(panel2, PANEL2); //create button to allow chnage to next card JButton buttonNext = new JButton(">"); buttonNext.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { CardLayout cl = (CardLayout) (cards.getLayout());//get cards cl.next(cards); } }); //create button to allow chnage to previous card JButton buttonPrev = new JButton("<"); buttonPrev.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { CardLayout cl = (CardLayout) (cards.getLayout());//get cards cl.previous(cards); } }); //create panel to hold buttons which will allow switching between cards JPanel buttonPanel = new JPanel(); buttonPanel.add(buttonPrev); buttonPanel.add(buttonNext); frame.add(cards); frame.add(buttonPanel, BorderLayout.SOUTH); frame.pack(); frame.setVisible(true); } } 

2)使用removeAll()技术,即调用frame.getContentPane().removeAll() ,它将删除当前在JFrame上的所有组件,然后添加新内容并调用revalidate()repaint() (也可能想要添加pack()在那里)在JFrame实例上反映变化。 虽然我推荐CardLayout

我想你可以使用CardLayout来实现你的function。 请参考这里