¿Cómo cambio JPanel dentro de un JFrame sobre la marcha?

Para decirlo de manera simple, hay una aplicación Java simple que consta de JFrame con algunos componentes. Uno de los componentes es un JPanel que debe reemplazarse por otro JPanel en la acción del usuario.

Entonces, ¿cuál es la forma correcta de hacer tal cosa? He intentado

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

pero esto no funcionará ¿Qué sugieres?

Su caso de uso, parece perfecto para CardLayout .

En el diseño de la tarjeta, puede agregar varios paneles en el mismo lugar, pero luego mostrar u ocultar, un panel a la vez.

1) Configurando el primer Panel:

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

2) Reemplazar el panel:

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

También tenga en cuenta que debe hacer esto en el subproceso del evento, para asegurar que use SwingUtilities.invokeLater o SwingWorker.

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

Recuerde, el uso de Java ‘copiar referencia por valor’ pasa el argumento. Entonces, cambiar una variable no cambiará las copias de la referencia pasada a otros métodos.

También tenga en cuenta que JFrame es muy confuso en el nombre de usabilidad. Agregar un componente o establecer un diseño (normalmente) realiza la operación en el panel de contenido. Por extraño que parezca, obtener el diseño realmente te da el administrador de diseño del marco.

Espero que esta pieza de código te dé una idea de cómo cambiar jPanels dentro de 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); } } 

En la acción del usuario:

// tienes que hacer algo a lo largo de las líneas de

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

Luego puede cambiar el tamaño de su wndow según sea necesario.

Todo depende de cómo va a ser utilizado. Si desea cambiar entre estos dos paneles, utilice CardLayout. Si solo está cambiando de la primera a la segunda vez (y no regresando), entonces usaría la sugerencia de telcontar y simplemente la reemplazaría. Aunque si el JPanel no es lo único en su marco, usaría remove (java.awt.Component) en lugar de removeAll.

Si se encuentra en algún punto intermedio entre estos dos casos, básicamente se trata de una compensación de tiempo-espacio. CardLayout le ahorrará tiempo pero ocupará más memoria al tener que mantener todo este otro panel en la memoria en todo momento. Pero si solo reemplaza el panel cuando es necesario y lo construye según demanda, no tiene que mantener ese meory pero le lleva más tiempo cambiarlo.

También puedes probar un JTabbedPane para usar tabs en su lugar (es incluso más fácil que CardLayout porque maneja el mostrar / ocultar automáticamente)

Los otros individuos respondieron la pregunta. Quiero sugerirle que use un JTabbedPane en lugar de reemplazar el contenido. Como regla general, es malo que los elementos visuales de su aplicación desaparezcan o sean reemplazados por otro contenido. Ciertamente, hay excepciones para cada regla, y solo usted y su comunidad de usuarios pueden decidir el mejor enfoque.

¡Estaba teniendo exactamente el mismo problema! ¡Increíble! La solución que encontré fue:

  1. Agregar todos los componentes (JPanels) al contenedor;
  2. Usando el método setVisible (falso) para todos ellos;
  3. En la acción del usuario, estableciendo setVisible (verdadero) en el panel que quería mostrar.
 // 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); 

No revalidar (), no validar (), no se necesita CardLayout.

La respuesta layout.replace () solo existe / funciona en GroupLayout Manager.

Otros administradores de diseño (CardLayout, BoxLayout, etc.) NO son compatibles con esta característica, pero requieren que primero RemoveLayoutComponent (y luego AddLayoutComponent (de nuevo. 🙂 [Simplemente estableciendo el registro en línea recta]

Le sugiero que agregue ambos paneles en la creación del cuadro, luego cambie el panel visible llamando a setVisible (verdadero / falso) en ambos. Al llamar a setVisible, se notificará al padre y se le pedirá que vuelva a pintar.

 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 veces puedes hacer el trabajo sin utilizar la revalidación y, a veces, sin utilizar el repintado. Mi consejo es usar ambos.

Problema : mi componente no aparece después de que lo agregué al contenedor.

Debe invocar revalidar y volver a pintar después de agregar un componente antes de que aparezca en su contenedor.

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

Simplemente llame al paquete de métodos () después de configurar el ContentPane , ( java 1.7 , quizás más antiguo) de la siguiente manera:

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

puede usar el método de reemplazo de un diseño:

 layout.replace(existingComponent, newComponent) 

los componentes existentes y nuevos también pueden ser JPanels.