2010-03-12 9 views
29

Ich fand ein Beispiel, in denen Schaltflächen zu Panels hinzugefügt werden (Instanzen von JPanel) dann Panels zu den Containern hinzugefügt werden (Instanzen generiert von getContentPane()) und Container sind durch die Konstruktion in die JFrame (die Fenster) enthalten.Was ist die Beziehung zwischen ContentPane und JPanel?

Ich habe versucht, zwei Dinge:

  1. ich die Behälter losgeworden. Genauer gesagt, habe ich Schaltflächen zu einem Panel hinzugefügt (Instanz JPanel) und dann habe ich das Panel zu den Fenstern hinzugefügt (Instanz JFrame). Es hat gut funktioniert.

  2. Ich habe die Panels los. Genauer gesagt habe ich Schaltflächen direkt zum Container hinzugefügt und dann den Container zum Fenster hinzugefügt (Instanz JFrame).

So verstehe ich zwei Dinge nicht.

  1. Warum haben wir zwei konkurrierende Mechanismen, um die gleichen Dinge zu tun?

  2. Warum werden Behälter in Kombination mit den Platten verwendet (JPanel)? (Zum Beispiel, was wir für Buttons in JPanels haben, und dann fügen wir JPanels in die Container ein). Können wir JPanel in JPanel einschließen? Können wir einen Container in einen Container aufnehmen?

ZUSÄTZLICH:

Vielleicht Essenz meiner Frage kann in einer Codezeile gesetzt werden:

frame.getContentPane().add(panel); 

Was für wir getContentPane() setzen dazwischen? Ich habe versucht, nur frame.add(panel); und es funktioniert gut.

2 Addiert:

Ich mag würde einige Code hinzufügen, um mehr klar, was ich meine. In diesem Beispiel verwende ich nur 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); 
    } 
} 

Und in diesem Beispiel verwende ich nur Inhaltsfenster:

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

Beide arbeiten gut! Ich möchte nur wissen, ob zwischen diesen beiden Arten, Dinge zu tun, einer besser (sicherer) ist.

Antwort

27

Es ist nicht zwei konkurrierende Mechanismen - ein JPanelist einContainer (schauen Sie in der Klassenhierarchie an der Spitze der JPanel javadocs). JFrame.getContentPane() gibt einfach eine Container zurück, um die Component s, die Sie in der JFrame anzeigen möchten, zu platzieren. Intern verwendet es eine JPanel (standardmäßig - Sie können dies ändern, indem Sie setContentPane() aufrufen) Wie für warum es eine Container anstelle einer JPanel zurückgibt - es ist, weil Sie program to an interface, not an implementation - auf dieser Ebene, alles, was Sie kümmern müssen, ist, dass Sie kann Component s zu etwas hinzufügen - und obwohl Container ist eine Klasse und nicht eine Schnittstelle - es bietet die Schnittstelle benötigt, um genau das zu tun.

Was, warum beide JFrame.add() und JFrame.getContentPane().add() beide das gleiche tun - JFrame.add() ist außer Kraft gesetzt JFrame.getContentPane().add() zu nennen. Dies war nicht immer der Fall - vor JDK 1.5 musste man immer JFrame.getContentPane().add() explizit angeben und JFrame.add() warf einen RuntimeException wenn man es anrief, aber aufgrund vieler Beschwerden wurde dies in JDK 1.5 geändert, um das zu tun, was man erwarten würde.

+0

@Nate, was meinst du mit "Intern, es ist ein JPanel". Sie meinen, dass Container ein JPanel verwendet? Was meinst du damit? Ich denke, dass JPanel eine Unterklasse von Container ist. Und was kann ich mit "setContentPane" ändern? OK. Sie sagen, Container ist eine Klasse (und ich habe Container immer als Klasse betrachtet). Aber JPane ist auch eine Klasse. Warum können wir nicht nur JPane oder nur Container verwenden?Ich konnte die gleichen Dinge tun, indem ich nur JPane verwendete. Ich konnte dasselbe auch nur mit Containern tun. – Roman

+0

'JFrame' verwendet intern ein' JPanel' -Objekt, um die 'getContentPane()' -Methode zu unterstützen. Deshalb funktioniert Zacharys Antwort. Die tatsächliche 'JPanel'-Referenz ist im' JFrame.rootPane'-Feld vergraben. Sie würden 'setContentPane()' auf dem 'JFrame' aufrufen - zum Beispiel könnten Sie Zeile 10 in Ihrem ersten Beispiel von' frame.add (panel) 'in' frame.setContentPane (panel) 'ändern. Container ist eine Klasse. 'JPanel' ist eine Klasse (die eine Unterklasse von' Container' ist). Sie verwechseln den Typ der Referenz mit dem Typ des Objekts, auf das die Referenz verweist. Denken Sie an 'Container container = new JPanel()' – Nate

+0

@Nate die Quelle (http://pragmaticjava.blogspot.com.ar/2008/08/program-to-interface-not-implementation.html) wurde entfernt. – Lucio

1

Ich glaube der Grund ist, weil Swing von AWT gebaut wurde, und Container ist ein Top-Level-AWT-Objekt. Es ist jedoch nicht die beste Design-Wahl, da man AWT (Schwergewicht) Objekte generell nicht mit Swing (leicht) kombinieren möchte.

Ich denke, der beste Weg, damit umzugehen, ist, den contentPane immer zu einem JPanel zu werfen.

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

Es ist nicht Mischen von AWT und Swing-Komponenten ... siehe meine Antwort – Nate

1

Alles in der letzten Version geschrieben API doc die JFrame.add() (nowerdays) genug ist.

Sie können mit älteren Java-Versionen here vergleichen.

3

Gute Frage. Ich fand es hilfreich zu verstehen, dass "Swing bietet drei allgemein nützliche Top-Level-Container-Klassen: JFrame, JDialog und JApplet. ... Als Annehmlichkeit, die add-Methode und ihre Varianten, entfernen und setLayout wurden überschrieben, um an die contentPane als notwendig. "- Using Top-Level Containers

1

interessant: jframe.setBackground(color) funktioniert nicht für mich, aber jframe.getContentPane().setBackground(color) funktioniert.

1

Die Geschichte und die Mechanik davon werden ebenfalls ausführlich unter this leepoint article diskutiert. Insbesondere ist zu beachten:

getContentPane() gibt ein Container Objekt. Dies ist nicht wirklich ein einfaches Container Objekt, aber ist eigentlich ein JPanel! Dies ist ein Container als Folge der Hierarchie. Wenn wir also den vordefinierten Inhaltsbereich aufrufen, stellt sich heraus, dass es tatsächlich ein JPanel ist, aber wir können die Funktionalität, die von JComponent hinzugefügt wurde, wirklich nicht nutzen.

und

Sie definierten add() Methoden in JFrame die einfach die entsprechenden add() Methoden zur Inhaltsbereich nennen. Es ist merkwürdig, dieses Feature jetzt hinzuzufügen, besonders da viele Layouts mehrere verschachtelte Panels verwenden, so dass Sie immer noch bequem mit dem Hinzufügen direkt zu einem JPanel umgehen können. Und nicht alles, was Sie mit dem Inhaltsfenster tun möchten, kann über Aufrufe an die JFrame erfolgen.

Verwandte Themen