java - layouts - ¿Cuál es la relación entre ContentPane y JPanel?
layouts java swing (6)
Buena pregunta. Me resultó útil comprender que "Swing ofrece tres clases de contenedores de primer nivel generalmente útiles: JFrame
, JDialog
y JApplet
. Como conveniencia, el método add y sus variantes, remove y setLayout se han reemplazado para reenviar al contentPane según sea necesario. "- Uso de contenedores de nivel superior
Encontré un ejemplo en el que los botones se agregan a los paneles (instancias de JPanel
) luego los paneles se agregan a los contenedores (instancias generadas por getContentPane()
) y luego los contenedores son, por la construcción, incluidos en el JFrame
(las ventanas).
Intenté dos cosas:
Me deshice de los contenedores. En más detalles, agregué botones a un panel (instancia de
JPanel
) y luego agregué el panel a las ventanas (instancia deJFrame
). Funcionó bienMe deshice de los paneles. En más detalles, agregué botones directamente al contenedor y luego agregué el contenedor a la ventana (instancia de
JFrame
).
Entonces, no entiendo dos cosas.
¿Por qué tenemos dos mecanismos en competencia para hacer las mismas cosas?
¿Cuál es la razón para usar contenedores en combinación con los paneles (
JPanel
)? (Por ejemplo, para qué incluimos botones en JPanels y luego incluimos JPanels en los Contenedores). ¿Podemos incluirJPanel
enJPanel
? ¿Podemos incluir un contenedor en un contenedor?
ADICIONAL:
Quizás la esencia de mi pregunta se puede poner en una línea de código:
frame.getContentPane().add(panel);
¿Para qué ponemos getContentPane()
en medio? Intenté solo frame.add(panel);
y funciona bien
AGREGADO 2:
Me gustaría agregar un código para ser más claro sobre lo que quiero decir. En este ejemplo, uso solo JPane:
import java.awt.*;
import javax.swing.*;
public class HelloWorldSwing {
public static void main(String[] args) {
JFrame frame = new JFrame("HelloWorldSwing");
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JButton("W"), BorderLayout.NORTH);
panel.add(new JButton("E"), BorderLayout.SOUTH);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
Y en este ejemplo, uso solo el Panel de contenido:
import java.awt.*;
import javax.swing.*;
public class HelloWorldSwing {
public static void main(String[] args) {
JFrame frame = new JFrame("HelloWorldSwing");
Container pane = frame.getContentPane();
pane.setLayout(new BorderLayout());
pane.add(new JButton("W"), BorderLayout.NORTH);
pane.add(new JButton("E"), BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
¡Ambos funcionan bien! Solo quiero saber si entre estas dos formas de hacer las cosas, una es mejor (más segura).
Creo que la razón es porque Swing se creó a partir de AWT, y Container es un objeto AWT de nivel superior. En realidad, no es la mejor opción de diseño, ya que generalmente no desea mezclar objetos AWT (peso pesado) con Swing (peso ligero).
Creo que la mejor manera de manejarlo es lanzar siempre el contenidoPanel a un JPanel.
JPanel contentPanel = (JPanel)aFrame.getContentPane();
Interesante: jframe.setBackground(color)
no funciona para mí, pero funciona jframe.getContentPane().setBackground(color)
.
La historia y la mecánica de esto también se discuten con cierto detalle en este artículo de punto de vista . Nota en particular:
getContentPane()
devuelve un objetoContainer
. ¡Este no es realmente un objetoContainer
simple, pero en realidad es unJPanel
! Este es unContainer
como consecuencia de la jerarquía. Entonces, si obtenemos el panel de contenido predefinido, resulta que en realidad es unJPanel
, pero realmente no podemos aprovechar la funcionalidad que fue agregada porJComponent
.
y
Definieron métodos
add()
enJFrame
que simplemente llaman a los métodosadd()
correspondientes para el panel de contenido. Parece extraño agregar esta característica ahora, especialmente debido a que muchos diseños usan múltiples paneles anidados, por lo que aún debe sentirse cómodo al agregarlos directamente a unJPanel
. Y no todo lo que desea hacer con el panel de contenido se puede hacer a través de llamadas aJFrame
.
No se trata de dos mecanismos que compiten: un JPanel
es un Container
(basta con mirar la jerarquía de clases en la parte superior de los Javavacs de JPanel ). JFrame.getContentPane()
simplemente devuelve un Container
para colocar los Component
que desea mostrar en el JFrame
. Internamente, está usando un JPanel
(de manera predeterminada, puede cambiar esto llamando a setContentPane()
) En cuanto a por qué devuelve un Container
lugar de un JPanel
, es porque debe programar una interfaz, no una implementación , en ese nivel, todo Lo que necesita preocuparse es que puede agregar Component
a algo, y aunque Container
es una clase en lugar de una interfaz, proporciona la interfaz necesaria para hacer exactamente eso.
En cuanto a por qué tanto JFrame.add()
como JFrame.getContentPane().add()
hacen lo mismo: JFrame.add()
se reemplaza para llamar a JFrame.getContentPane().add()
. Este no era siempre el caso: antes de JDK 1.5, siempre tenía que especificar JFrame.getContentPane().add()
explícitamente y JFrame.add()
lanzaba RuntimeException
si lo llamaba, pero debido a muchas quejas, esto se cambió en JDK 1.5 para hacer lo que esperas.