如何通过单击 JButton 添加 JPanel?
Posted
技术标签:
【中文标题】如何通过单击 JButton 添加 JPanel?【英文标题】:How to add JPanel by clicking JButton? 【发布时间】:2012-12-10 06:55:33 【问题描述】:我正在尝试创建一个小型 GUI,它有 2 个 JButton 和 2 个 JPanel,每个都有一些绘图动画。默认情况下,它必须显示第一个 JPanel,通过单击第二个 JButton,我想查看我的第二个 JPanel。所以:我创建了 JFrame、Panel1 和 Panel2,在那里我绘制了我的动画,创建了 Button1 和 Button2 并向它们添加了 ActionListener。我还有 MainPanel,它在字段变量 i 中。通过更改此“i”,我的构造函数将 Panel1(默认)或 Panel2(通过单击 JButton2 我更改 i)添加到 MainPanel。比我将此 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();
);
【问题讨论】:
【参考方案1】:为了在添加/删除或调整可见容器上的组件后反映更改,在添加/删除或调整组件大小后,在容器实例上调用 revalidate()
和 repaint()
。
虽然这在您的代码中不起作用,但主要原因是在 JButton 类中,您重新创建 MainPanel
的新实例,而实际上 2 JButtons
应该共享正在使用的单个实例(您可以传递 MainPanel 实例到JButton
s 构造函数,但你不应该真正扩展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(..)
块,阅读here 了解更多信息。
这是您的代码已修复(上述建议等已实施):
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);
不过我建议一些更简单的东西,幸运的是你有 2 个选择:
1) 使用CardLayout
,这将允许您在单个JFrame
/container 上的多个组件之间切换。
这是我做的一个例子:
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()
in那里)在JFrame
实例上以反映更改。虽然我推荐CardLayout
。
【讨论】:
感谢您更正我的代码和示例,这很有帮助!是的,CardLayout 解决了我的问题。【参考方案2】:我认为您可以使用CardLayout
来实现您的功能。请参考here
【讨论】:
以上是关于如何通过单击 JButton 添加 JPanel?的主要内容,如果未能解决你的问题,请参考以下文章
为什么我的JButton在放入JPanel的构造函数时不显示?
如何使用默认 FlowLayout 在 JPanel 中将 JButton 居中?