2010-03-12 23 views
29

Encontré un ejemplo en el que se agregan botones a paneles (instancias de JPanel) luego se agregan paneles a los contenedores (instancias generadas por getContentPane()) y luego los contenedores son, por la construcción, incluidos en JFrame (las ventanas).¿Cuál es la relación entre ContentPane y JPanel?

probé dos cosas:

  1. que se deshizo de los contenedores. En más detalles, agregué botones a un panel (instancia de JPanel) y luego agregué el panel a las ventanas (instancia de JFrame). Funcionó bien

  2. Me 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.

  1. ¿Por qué tenemos dos mecanismos que compiten para hacer las mismas cosas?

  2. ¿Cuál es el motivo para utilizar contenedores en combinación con los paneles (JPanel)? (Por ejemplo, para qué incluimos botones en JPanels y luego incluimos JPanels en los Contenedores). ¿Podemos incluir JPanel en JPanel? ¿Podemos incluir un contenedor en un contenedor?

añadido:

Tal esencia de mi pregunta se puede poner en una línea de código:

frame.getContentPane().add(panel); 

Lo que para getContentPane() ponemos en el medio? Intenté solo frame.add(panel); y funciona bien.

añadieron 2:

me gustaría añadir algo de código para ser más claro acerca de lo que quiero decir. En este ejemplo utilizo solamente 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 utilizo Panel única 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).

Respuesta

27

No son dos mecanismos que compiten - un JPaneles unContainer (basta con ver la jerarquía de clases en la parte superior de la JPanel javadocs). JFrame.getContentPane() acaba de devolver un Container para colocar el Component s que desea mostrar en el JFrame. Internamente, está utilizando un JPanel (de manera predeterminada, puede cambiar esto llamando al setContentPane()) En cuanto a por qué devuelve un Container en lugar de un - es porque debe program to an interface, not an implementation - en ese nivel, todo lo que necesita preocuparse es que usted puede agregar Component s a algo, y aunque Container es una clase en lugar de una interfaz, proporciona la interfaz necesaria para hacer exactamente eso.

cuanto a por qué tanto JFrame.add() y JFrame.getContentPane().add() ambos hacen lo mismo - JFrame.add() se reemplaza para llamar JFrame.getContentPane().add(). Este no fue siempre el caso: antes de JDK 1.5 siempre tenía que especificar JFrame.getContentPane().add() explícitamente y JFrame.add() lanzó un RuntimeException si lo llamó, pero debido a muchas quejas, esto se cambió en JDK 1.5 para hacer lo que cabría esperar.

+0

@Nate, ¿qué quiere decir con "Internamente, está usando un JPanel". ¿Quieres decir que Container está usando un JPanel? ¿Qué quieres decir con eso? Pensé que JPanel es una subclase de Container. ¿Y qué puedo cambiar por "setContentPane"? DE ACUERDO. Usted dice que Container es una clase (y siempre consideré Container como clase). Pero JPane también es una clase. ¿Por qué no podemos usar solo JPane o simplemente Container?Pude hacer lo mismo usando solo JPane. También pude hacer lo mismo usando solo Contenedores. – Roman

+0

'JFrame' utiliza internamente un objeto' JPanel' para respaldar el método 'getContentPane()'. Esta es la razón por la cual la respuesta de Zachary funciona. La referencia real de 'JPanel' está enterrada en el campo' JFrame.rootPane'. Llamarías a 'setContentPane()' en 'JFrame'; por ejemplo, podrías cambiar la línea 10 en tu primer ejemplo de' frame.add (panel) 'a' frame.setContentPane (panel) '. 'Container' es una clase. 'JPanel' es una clase (que es una subclase de' Container'). Está confundiendo el tipo de referencia con el tipo de objeto al que hace referencia la referencia. Piense en 'Container container = new JPanel()' – Nate

+0

@Nate la fuente (http://pragmaticjava.blogspot.com.ar/2008/08/program-to-interface-not-implementation.html) ha sido eliminada. – Lucio

1

Creo que la razón es porque Swing se creó a partir de AWT, y el contenedor 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 siempre lanzar el panel de contenido a un JPanel.

JPanel contentPanel = (JPanel)aFrame.getContentPane(); 
+0

No está mezclando los componentes AWT y Swing ... ver mi respuesta – Nate

1

todo está escrito en la última versión API doc que JFrame.add() (nowerdays) es suficiente.

Puede comparar con versiones anteriores de Java here.

3

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. "- Using Top-Level Containers

1

interesante: jframe.setBackground(color) no funciona, pero jframe.getContentPane().setBackground(color) funciona.

1

La historia y la mecánica de esto también se discuten en detalle en this leepoint article. Nota en particular:

getContentPane() devuelve un objeto Container. ¡Este no es realmente un objeto simple Container, pero en realidad es JPanel! Esto es Container como consecuencia de la jerarquía. Entonces, si obtenemos el panel de contenido predefinido, resulta que en realidad es JPanel, pero realmente no podemos aprovechar la funcionalidad que se agregó en JComponent.

y

definieron add() métodos en JFrame que simplemente llamar a la add() métodos correspondientes para el panel de contenido. Parece extraño agregar esta función 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 JPanel. Y no todo lo que desee hacer con el panel de contenido se puede hacer a través de llamadas al JFrame.

Cuestiones relacionadas