Come posso cambiare JPanel all’interno di un JFrame al volo?

Per dirla in modo semplice, c’è una semplice app java swing che consiste in JFrame con alcuni componenti al suo interno. Uno dei componenti è un JPanel che deve essere sostituito da un altro JPanel sull’azione dell’utente.

Quindi, qual è il modo corretto di fare una cosa del genere? ho provato

panel = new CustomJPanelWithComponentsOnIt(); parentFrameJPanelBelongsTo.pack(); 

ma questo non funzionerà. Che cosa suggeriresti?

Il tuo caso d’uso, sembra perfetto per CardLayout .

Nel layout delle carte puoi aggiungere più pannelli nello stesso posto, ma poi mostrare o hide, un pannello alla volta.

1) Impostazione del primo pannello:

 JFrame frame=new JFrame(); frame.getContentPane().add(new JPanel()); 

2) Sostituzione del pannello:

 frame.getContentPane().removeAll(); frame.getContentPane().add(new JPanel()); 

Si noti inoltre che è necessario eseguire questa operazione nella Discussione dell’evento per assicurarsi di utilizzare SwingUtilities.invokeLater o SwingWorker

 frame.setContentPane(newContents()); frame.revalidate(); // frame.pack() if you want to resize. 

Ricorda, Java usa l’argomento ‘copia riferimento per valore’ passando. Quindi, cambiando una variabile, non cambierai le copie del riferimento passato ad altri metodi.

Nota anche che JFrame è molto confuso nel nome dell’usabilità. L’aggiunta di un componente o l’impostazione di un layout (in genere) esegue l’operazione nel riquadro del contenuto. Stranamente, ottenere il layout ti dà davvero il gestore del layout del frame.

Spero che questo pezzo di codice ti dia un’idea di come cambiare jPanel all’interno di un JFrame.

 public class PanelTest extends JFrame { Container contentPane; public PanelTest() { super("Changing JPanel inside a JFrame"); contentPane=getContentPane(); } public void createChangePanel() { contentPane.removeAll(); JPanel newPanel=new JPanel(); contentPane.add(newPanel); System.out.println("new panel created");//for debugging purposes validate(); setVisible(true); } } 

Sull’azione dell’utente:

// devi fare qualcosa sulla falsariga di

 myJFrame.getContentPane().removeAll() myJFrame.getContentPane().invalidate() myJFrame.getContentPane().add(newContentPanel) myJFrame.getContentPane().revalidate() 

Quindi puoi ridimensionare il tuo wndow secondo necessità.

Tutto dipende da come sarà usato. Se si desidera passare avanti e indietro tra questi due pannelli, utilizzare CardLayout. Se passi solo dalla prima alla seconda volta e (e non torni indietro), allora utilizzerei il suggerimento di telcontar e lo sostituirò. Anche se il JPanel non è l’unica cosa nel tuo frame, userei remove (java.awt.Component) invece di removeAll.

Se sei da qualche parte tra questi due casi, è fondamentalmente un compromesso spazio-tempo. CardLayout ti farà risparmiare tempo ma occuperà più memoria tenendo sempre tutto l’altro pannello in memoria. Ma se si sostituisce semplicemente il pannello quando necessario e lo si costruisce su richiesta, non è necessario mantenerlo in memoria ma richiede più tempo per il passaggio.

Puoi anche provare un JTabbedPane per usare le tab invece (è ancora più semplice di CardLayout perché gestisce automaticamente la visualizzazione / la mascheratura)

Gli altri individui hanno risposto alla domanda. Voglio suggerirti di usare JTabbedPane invece di sostituire il contenuto. Come regola generale, è brutto che gli elementi visivi della tua applicazione scompaiano o vengano sostituiti da altri contenuti. Certamente ci sono delle eccezioni a ogni regola e solo tu e la tua comunità di utenti potete decidere l’approccio migliore.

Stavo avendo esattamente lo stesso problema !! Chetumal !! La soluzione che ho trovato è stata:

  1. Aggiunta di tutti i componenti (JPanels) al contenitore;
  2. Usando il metodo setVisible (false) per tutti loro;
  3. Sull’azione dell’utente, imposta setVisible (true) sul pannello che volevo mostrare.
 // Hiding all components (JPanels) added to a container (ex: another JPanel) for (Component component : this.container.getComponents()) { component.setVisible(false); } 
 // Showing only the selected JPanel, the one user wants to see panel.setVisible(true); 

Nessuna convalida (), nessuna convalida (), nessun CardLayout necessario.

La risposta layout.replace () esiste solo / funziona su GroupLayout Manager.

Altri LayoutManager (CardLayout, BoxLayout, ecc.) NON supportano questa funzione, ma richiedono di rimuovere RemoveLayoutComponent (e quindi AddLayoutComponent (di nuovo indietro 🙂 [Basta impostare il record direttamente]

Vi suggerisco di aggiungere entrambi i pannelli alla creazione del frame, quindi modificare il pannello visibile chiamando setVisible (true / false) su entrambi. Quando si chiama setVisible, il genitore riceverà una notifica e gli verrà chiesto di ridisegnarsi.

 class Frame1 extends javax.swing.JFrame { remove(previouspanel); //or getContentPane().removeAll(); add(newpanel); //or setContentPane(newpanel); invalidate(); validate(); // or ((JComponent) getContentPane()).revalidate(); repaint(); //DO NOT FORGET REPAINT } 

A volte è ansible eseguire il lavoro senza utilizzare la riconvalida e talvolta senza utilizzare il ridisegno. È consigliabile utilizzare entrambi.

Problema : il mio componente non viene visualizzato dopo averlo aggiunto al contenitore.

È necessario invocare rinnova e ridisegna dopo aver aggiunto un componente prima che venga visualizzato nel contenitore.

Fonte: http://docs.oracle.com/javase/tutorial/uiswing/layout/problems.html

Basta chiamare il metodo pack () dopo aver impostato ContentPane , ( java 1.7 , forse più vecchio) in questo modo:

 JFrame frame = new JFrame(); JPanel panel1 = new JPanel(); JPanel panel2 = new JPanel(); .... frame.setContentPane(panel1); frame.pack(); ... frame.setContentPane(panel2); frame.pack(); ... 

puoi usare il metodo di sostituzione di un layout:

 layout.replace(existingComponent, newComponent) 

le componenti esistenti e nuove possono essere anche JPanels.