2012-12-23 19 views
5

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 classe MainPanel ho il metodo refreshMe, cosa dovrei scrivere lì per far funzionare correttamente la mia GUI? Grazie. Ecco il mio codice:Come aggiungere JPanel facendo clic su JButton?

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

    } 

} 

risposta

8

Al fine di riflettere modifiche dopo l'aggiunta/rimozione o ridimensionare un componente che è su un contenitore chiamata visibile revalidate() e repaint() sull'istanza contenitori dopo l'aggiunta/rimozione o ridimensionare il componente.

Anche se questo non funziona nel codice il motivo principale è dentro le classi JButton di ricreare una nuova istanza di MainPanel quando in realtà il 2 JButtons dovrebbero condividere la singola istanza che viene utilizzato (potreste passare esempio MainPanel al JButton s costruttori, ma non si dovrebbe davvero essere estende un JButton a meno che l'aggiunta di 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 codice:

  • Non estendere la classe JButton inutilmente, è sufficiente creare un'istanza di JButton come si è fatto con JFrame e chiamare i metodi sull'istanza JButton.

  • Non dimenticate di creare/manipolare i componenti Swing on Event Dispatch Thread, via SwingUtilities.invokeLater(..) blocco, leggere here di più.

Ecco il tuo codice fisso (sopra suggerimenti ect implementata):

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

Tuttavia Id suggeriscono qualcosa di più semplice, per fortuna si hanno 2 scelte:

1) Utilizzare CardLayout che vi permetterà di sfogliare più componenti su un singolo JFrame/contenitore.

Ecco un esempio che ho fatto:

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) Utilizzare removeAll() tecnica cioè chiamata frame.getContentPane().removeAll() che rimuoverà tutti i componenti attualmente in JFrame e poi aggiungere il nuovo contenuto e chiamare revalidate() e repaint() (potrebbe anche essere necessario aggiungere pack()) nell'istanza JFrame per riflettere le modifiche. Sebbene Id raccomandi CardLayout.

+0

Grazie per aver corretto il mio codice e l'esempio, questo aiuta molto! Sì, CardLayout risolve il mio problema. – user1924939

3

Penso che si può semplicemente utilizzare CardLayout per implementare la funzione. Consultare here

Problemi correlati