2010-03-12 6 views
29

Ho trovato un esempio in cui i pulsanti vengono aggiunti ai pannelli (istanze di JPanel), quindi i pannelli vengono aggiunti ai contenitori (istanze generate da getContentPane()) e quindi i contenitori sono inclusi nella JFrame (le finestre).Qual è la relazione tra ContentPane e JPanel?

Ho provato due cose:

  1. mi sono liberato dei contenitori. In ulteriori dettagli, ho aggiunto pulsanti a un pannello (istanza di JPanel) e quindi ho aggiunto il pannello a Windows (istanza di JFrame). Ha funzionato bene.

  2. Mi sono liberato dei pannelli. In ulteriori dettagli, ho aggiunto pulsanti direttamente al contenitore e quindi ho aggiunto il contenitore alla finestra (istanza di JFrame).

Quindi, non capisco due cose.

  1. Perché abbiamo due meccanismi in competizione per fare le stesse cose?

  2. Qual è la ragione per utilizzare i contenitori in combinazione con i pannelli (JPanel)? (Ad esempio, per quanto includiamo i pulsanti in JPanels e quindi includiamo JPanel nei Containers). Possiamo includere JPanel in JPanel? Possiamo includere un contenitore nel contenitore?

aggiunto:

Forse essenza della mia domanda può essere messo in una riga di codice:

frame.getContentPane().add(panel); 

Ciò che per mettiamo getContentPane() in mezzo? Ho provato solo frame.add(panel); e funziona perfettamente.

Aggiunto 2:

vorrei aggiungere del codice ad essere più chiari su quello che voglio dire. In questo esempio, io 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); 
    } 
} 

E in questo esempio io uso solo Content Pane:

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

Entrambi lavorano bene! Voglio solo sapere se tra questi due modi di fare le cose è meglio (più sicuro).

risposta

27

E 'non due concorrenti meccanismi - un JPanelè unContainer (basta guardare la gerarchia delle classi in cima alla JPanel javadocs). JFrame.getContentPane() restituisce appena un Container per posizionare i Component s che si desidera visualizzare nello JFrame. Internamente, sta usando un JPanel (per impostazione predefinita - è possibile modificare questo chiamando setContentPane()) Per quanto riguarda perché sta restituendo un Container invece di un JPanel - è perché si dovrebbe program to an interface, not an implementation - a quel livello, tutto ciò che devi preoccuparti è che tu può aggiungere Component s a qualcosa - e anche se Container è una classe piuttosto che un'interfaccia - fornisce l'interfaccia necessaria per fare esattamente questo.

Per quanto riguarda il motivo per cui sia JFrame.add() e JFrame.getContentPane().add() entrambi fanno la stessa cosa - JFrame.add() viene sostituito da chiamare JFrame.getContentPane().add(). Non è sempre stato così: pre-JDK 1.5 hai sempre specificato esplicitamente JFrame.getContentPane().add() e JFrame.add() hai lanciato un RuntimeException se lo hai chiamato, ma a causa di molti reclami, questo è stato modificato in JDK 1.5 per fare ciò che ti aspetteresti.

+0

@Nate, cosa intendi con "Internamente, sta usando un JPanel". Vuoi dire che Container usa JPanel? Che cosa vuoi dire con questo? Penso che JPanel sia una sottoclasse di Container. E cosa posso cambiare con "setContentPane"? OK. Tu dici che Container è una classe (e ho sempre considerato Container come una classe). Ma JPane è anche una classe. Perché non possiamo usare solo JPane o semplicemente Container?Sono stato in grado di fare le stesse cose usando solo JPane. Sono stato anche in grado di fare lo stesso usando solo contenitori. – Roman

+0

'JFrame' utilizza internamente un oggetto' JPanel' per eseguire il metodo 'getContentPane()'. Questo è il motivo per cui la risposta di Zachary funziona. Il riferimento effettivo 'JPanel' è sepolto nel campo' JFrame.rootPane'. Chiameresti 'setContentPane()' su 'JFrame' - per esempio, potresti cambiare la riga 10 nel tuo primo esempio da' frame.add (pannello) 'a' frame.setContentPane (pannello) '. 'Container' è una classe. 'JPanel' è una classe (che è una sottoclasse di' Container'). Stai confondendo il tipo di riferimento con il tipo dell'oggetto i riferimenti di riferimento. Pensa a 'Container container = new JPanel()' – Nate

+0

@Nate source (http://pragmaticjava.blogspot.com.ar/2008/08/program-to-interface-not-implementation.html) è stato rimosso. – Lucio

1

Credo che il motivo sia dovuto al fatto che Swing è stato ricavato da AWT e Container è un oggetto AWT di livello superiore. In realtà non è la scelta di design più grande, dato che generalmente non si desidera mescolare oggetti AWT (pesanti) con Swing (leggero).

Penso che il modo migliore per gestirlo sia quello di trasmettere sempre contentPane a JPanel.

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

Non sta combinando componenti AWT e Swing ... vedere la mia risposta – Nate

1

E 'tutto scritto nella sua ultima versione API doc che JFrame.add() (nowerdays) è sufficiente.

È possibile confrontare le versioni precedenti di Java here.

3

Buona domanda. Ho trovato utile comprendere che "Swing fornisce tre classi di contenitore di primo livello generalmente utili: JFrame, JDialog e JApplet. ... Per comodità, il metodo di aggiunta e le sue varianti, remove e setLayout sono stati sovrascritti per inoltrare a contentPane se necessario. "- Using Top-Level Containers

1

interessante: jframe.setBackground(color) non funziona per me, ma jframe.getContentPane().setBackground(color) funziona.

1

La storia e la meccanica di questo sono anche discussi in dettaglio a this leepoint article. Nota in particolare:

getContentPane() restituisce un oggetto Container. Questo non è un semplice oggetto Container, ma in realtà è un JPanel! Questo è un Container come conseguenza della gerarchia. Quindi, se otteniamo il riquadro del contenuto predefinito, risulta che è in realtà un JPanel, ma non possiamo davvero sfruttare la funzionalità che è stata aggiunta da JComponent.

e

Essi definito add() metodi JFrame che semplicemente chiamano le corrispondenti add() metodi per il riquadro del contenuto. Sembra strano aggiungere questa funzione ora, soprattutto dal momento che molti layout utilizzano più pannelli nidificati, quindi è ancora necessario essere a proprio agio con l'aggiunta diretta a un JPanel. E non tutto quello che vuoi fare con il pannello dei contenuti può essere fatto attraverso le chiamate allo JFrame.