¿Cómo agregar JPanel haciendo clic en JButton?

Intento crear una pequeña GUI, tiene 2 JButtons, y 2 JPanels con algunas animaciones de dibujo en cada uno de ellos. Por defecto, debe mostrar primero JPanel, y al hacer clic en el segundo JButton, quiero ver mi segundo JPanel. Entonces: creo JFrame, Panel1 y Panel2, donde he dibujado mis animaciones, creo Button1 y Button2 y les agrego ActionListeners. También tengo MainPanel que tiene en una variable de campos i. Al cambiar esta “i” mi constructor agrega a MainPanel Panel1 (predeterminado) o Panel2 (al hacer clic en JButton2, cambio i). Luego agregué este Panel principal a mi marco. Entonces mi pregunta: en la clase MainPanel tengo el método refreshMe, ¿qué debo escribir allí para que mi GUI funcione correctamente? Gracias. Aquí está mi código:

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

Para reflejar los cambios después de agregar / eliminar o cambiar el tamaño de un componente que está en un contenedor visible, vuelva a revalidate() y repaint() en la instancia de los contenedores después de agregar / eliminar o cambiar el tamaño del componente.

Aunque esto no funcionará en su código, la razón principal es que dentro de las clases de JButton recree una nueva instancia de MainPanel cuando en realidad los 2 JButtons deberían compartir la única instancia que se está utilizando (podría pasar la instancia de JButton los constructores de JButton , pero no debería extender un JButton menos que agregue funcionalidad personalizada):

 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() { } } 

Algunas otras sugerencias sobre tu código:

  • No extienda la clase JButton innecesariamente, simplemente cree una instancia de JButton como lo hizo con JFrame y llame a métodos en la instancia de JButton .

  • No se olvide de crear / manipular componentes Swing en Event Dispatch Thread , a través del bloque SwingUtilities.invokeLater(..) , lea aquí para obtener más información.

Aquí está su código fijo (las sugerencias anteriores están implementadas):

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

Sin embargo, si sugiero algo más simple, afortunadamente tienes 2 opciones:

1) Use CardLayout que le permitirá CardLayout entre varios componentes en un solo JFrame / contenedor.

Aquí hay un ejemplo que hice:

enter image description here

 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) Use la técnica removeAll() , es decir, frame.getContentPane().removeAll() que eliminará todos los componentes actualmente en JFrame y luego agregará el nuevo contenido y call revalidate() y repaint() (también podría querer agregar el pack() allí) en la instancia de JFrame para reflejar los cambios. Aunque Id recomienda CardLayout .

Creo que puedes usar CardLayout para implementar tu función. Por favor refiérase aquí