web-dev-qa-db-fra.com

Quelle est la relation entre ContentPane et JPanel?

J'ai trouvé un exemple dans lequel des boutons sont ajoutés aux panneaux (instances de JPanel) puis des panneaux sont ajoutés aux conteneurs (instances générées par getContentPane()) et puis les conteneurs sont, par la construction, inclus dans le JFrame (les fenêtres).

J'ai essayé deux choses:

  1. Je me suis débarrassé des conteneurs. Plus en détail, j'ai ajouté des boutons à un panneau (instance de JPanel) puis j'ai ajouté le panneau aux fenêtres (instance de JFrame). Cela a bien fonctionné.

  2. Je me suis débarrassé des panneaux. Plus en détail, j'ai ajouté des boutons directement au conteneur puis j'ai ajouté le conteneur à la fenêtre (instance de JFrame).

Donc, je ne comprends pas deux choses.

  1. Pourquoi avons-nous deux mécanismes concurrents pour faire les mêmes choses?

  2. Quelle est la raison d'utiliser des conteneurs en combinaison avec les panneaux (JPanel)? (Par exemple, pour quoi nous incluons des boutons dans JPanels puis nous incluons JPanels dans les conteneurs). Pouvons-nous inclure JPanel dans JPanel? Pouvons-nous inclure un conteneur dans un conteneur?

AJOUTÉ:

Peut-être que l'essence de ma question peut être mise dans une seule ligne de code:

frame.getContentPane().add(panel);

Pourquoi avons-nous mis getContentPane() entre les deux? J'ai essayé juste frame.add(panel); et cela fonctionne très bien.

AJOUTÉ 2:

Je voudrais ajouter du code pour être plus clair sur ce que je veux dire. Dans cet exemple, j'utilise uniquement 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);
    }
}

Et dans cet exemple, j'utilise uniquement le volet de contenu:

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

Les deux fonctionnent bien! Je veux juste savoir si entre ces deux façons de faire les choses est meilleure (plus sûre).

31
Roman

Ce ne sont pas deux mécanismes concurrents - un JPanel est unContainer (juste regardez la hiérarchie des classes en haut de la JPanel javadocs ). JFrame.getContentPane() renvoie juste un Container pour placer les Components que vous souhaitez afficher dans le JFrame. En interne, il utilise un JPanel (par défaut - vous pouvez changer cela en appelant setContentPane()) Quant à savoir pourquoi il retourne un Container au lieu d'un JPanel - c'est parce que vous devriez programmer une interface, pas une implémentation - à ce niveau, tout ce dont vous avez besoin est que vous pouvez ajouter Components à quelque chose - et même si Container est une classe plutôt qu'une interface - elle fournit l'interface nécessaire pour faire exactement cela.

Quant à savoir pourquoi JFrame.add() et JFrame.getContentPane().add() font tous deux la même chose - JFrame.add() est remplacé pour appeler JFrame.getContentPane().add(). Ce n'était pas toujours le cas - avant JDK 1.5, vous deviez toujours spécifier JFrame.getContentPane().add() explicitement et JFrame.add() jetait un RuntimeException si vous l'appeliez, mais à cause de beaucoup plaintes, cela a été changé dans JDK 1.5 pour faire ce que vous attendez.

29
Nate

Bonne question. J'ai trouvé utile de comprendre que "Swing fournit trois classes de conteneurs de niveau supérieur généralement utiles: JFrame, JDialog et JApplet. ... Par commodité, l'ajout La méthode et ses variantes, remove et setLayout ont été remplacées pour être transmises au contentPane si nécessaire. "— Utilisation de conteneurs de niveau supérieur =

3
trashgod

intéressant: jframe.setBackground(color) ne fonctionne pas pour moi, mais jframe.getContentPane().setBackground(color) fonctionne.

1
DanPB

Tout est écrit dans la dernière version API doc que JFrame.add () (nowerdays) est suffisant.

Vous pouvez comparer aux anciennes versions Java versions ici .

1
PeterMmm

Je crois que la raison en est que Swing a été construit à partir d'AWT et que Container est un objet AWT de haut niveau. Ce n'est vraiment pas le meilleur choix de conception, car vous ne voulez généralement pas mélanger des objets AWT (lourds) avec Swing (légers).

Je pense que la meilleure façon de le gérer est de toujours lancer le contentPane sur un JPanel.

JPanel contentPanel = (JPanel)aFrame.getContentPane();
1
Zachary Wright

L'histoire et la mécanique de ceci sont également discutées en détail dans cet article leepoint . A noter en particulier:

getContentPane() renvoie un objet Container. Ce n'est pas vraiment un simple objet Container, mais c'est en fait un JPanel! Il s'agit d'un Container comme conséquence de la hiérarchie. Donc, si nous obtenons le volet de contenu prédéfini, il s'avère qu'il s'agit en fait d'un JPanel, mais nous ne pouvons vraiment pas profiter des fonctionnalités ajoutées par JComponent.

et

Ils ont défini les méthodes add() dans JFrame qui appellent simplement les méthodes add() correspondantes pour le volet de contenu. Il semble étrange d'ajouter cette fonctionnalité maintenant, d'autant plus que de nombreuses dispositions utilisent plusieurs panneaux imbriqués, vous devez donc toujours être à l'aise pour ajouter directement à un JPanel. Et tout ce que vous voulez faire avec le volet de contenu ne peut pas être fait via des appels à JFrame.

1
Pops