Come aggiungere JPanel facendo clic su JButton?

Sto provando a creare una piccola GUI, ha 2 JButtons e 2 JPanel con alcune animazioni di disegno su ognuno di essi. Per impostazione predefinita, deve mostrare il primo JPanel e facendo clic sul secondo JButton voglio vedere il mio secondo JPanel. Quindi: creo JFrame, Panel1 e Panel2, dove ho disegnato le mie animazioni, creato Button1 e Button2 e aggiungendo ActionListeners. Ho anche MainPanel che ha in una variabile di campi i. Modificando questo “i” il mio costruttore aggiunge a MainPanel Panel1 (impostazione predefinita) o Panel2 (facendo clic su JButton2 I modifica i). Poi aggiungo questo MainPanel al mio frame. Quindi la mia domanda: nella class MainPanel ho il metodo refreshMe, cosa dovrei scrivere lì per far funzionare correttamente la mia GUI? Grazie. Ecco il mio codice:

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 actionPerformsd 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 actionPerformsd(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 actionPerformsd(ActionEvent e) { someObj2.setI(2); System.out.println("The variable i is now: " + someObj2.i); someObj2.refreshMe(); } }); } } 

Per riflettere le modifiche dopo aver aggiunto / rimosso o ridimensionato un componente su un contenitore visibile, chiamare revalidate() e repaint() contenitori dopo aver aggiunto / rimosso o ridimensionato il componente.

Anche se questo non funzionerà nel tuo codice, il motivo principale è che all’interno delle classi JButton si ricrea una nuova istanza di MainPanel quando in realtà i 2 JButtons devono condividere la singola istanza che viene utilizzata (si potrebbe passare l’istanza di MainPanel ai costruttori di JButton , ma non dovresti davvero estendere un JButton meno di aggiungere funzionalità personalizzate):

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

Alcuni altri suggerimenti sul tuo codice:

  • Non estendere inutilmente la class JButton , crea semplicemente un’istanza di JButton come hai fatto con JFrame e chiama i metodi JButton .

  • Non dimenticare di creare / manipolare i componenti di Swing sul Event Dispatch Thread SwingUtilities.invokeLater(..) Event Dispatch Thread , tramite il SwingUtilities.invokeLater(..) , leggi qui per ulteriori informazioni.

Ecco il tuo codice corretto (sopra i suggerimenti ect implementati):

 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 actionPerformsd(ActionEvent e) { myPanel.setI(1); System.out.println("The variable i is now: " + myPanel.i); myPanel.refreshMe(); } }); button2.addActionListener(new ActionListener() { @Override public void actionPerformsd(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 actionPerformsd 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); } } 

Tuttavia Id suggerisce qualcosa di più semplice, fortunatamente hai 2 scelte:

1) Usa CardLayout che ti permetterà di CardLayout tra più componenti su un singolo JFrame / contenitore.

Ecco un esempio che ho fatto:

inserisci la descrizione dell'immagine qui

 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 actionPerformsd(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) Usa la tecnica removeAll() cioè chiama frame.getContentPane().removeAll() che rimuoverà tutti i componenti attualmente su JFrame e che aggiungerà il nuovo contenuto e chiamerà revalidate() e repaint() (potrebbe anche voler aggiungere pack() in là) JFrame per riflettere i cambiamenti. Sebbene Id raccomandi CardLayout .

Penso che tu possa semplicemente usare CardLayout per implementare la tua funzione. Si prega di fare riferimento qui