Какова связь между ContentPane и JPanel? - PullRequest
31 голосов
/ 12 марта 2010

Я нашел один пример, в котором кнопки добавляются в панели (экземпляры JPanel), затем панели добавляются в контейнеры (экземпляры, генерируемые getContentPane()), а затем контейнеры по конструкции включаются в JFrame (окна).

Я попробовал две вещи:

  1. Я избавился от контейнеров. Более подробно, я добавил кнопки на панель (экземпляр JPanel), а затем добавил панель к окнам (экземпляр JFrame). Работало нормально.

  2. Я избавился от панелей. Более подробно, я добавил кнопки непосредственно в контейнер, а затем добавил контейнер в окно (экземпляр JFrame).

Итак, я не понимаю двух вещей.

  1. Почему у нас есть два конкурирующих механизма, которые делают одно и то же?

  2. В чем причина использования контейнеров в сочетании с панелями (JPanel)? (Например, зачем мы включаем кнопки в JPanels, а затем мы включаем JPanels в контейнеры). Можем ли мы включить JPanel в JPanel? Можем ли мы включить контейнер в контейнер?

ДОБАВЛЕНО:

Может быть, суть моего вопроса можно заключить в одну строку кода:

frame.getContentPane().add(panel);

Зачем мы ставим getContentPane() между ними? Я попытался просто frame.add(panel);, и он отлично работает.

ДОБАВЛЕНО 2:

Я хотел бы добавить код, чтобы было более понятно, что я имею в виду. В этом примере я использую только 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);
    }
}

И в этом примере я использую только панель содержимого:

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

Оба работают отлично! Я просто хочу знать, если между этими двумя способами сделать что-то лучше (безопаснее).

Ответы [ 6 ]

29 голосов
/ 12 марта 2010

Это не два конкурирующих механизма - JPanel - это Container (просто посмотрите на иерархию классов в верхней части JPanel javadocs ). JFrame.getContentPane() просто возвращает Container, чтобы поместить Component s, которые вы хотите отобразить в JFrame. Внутренне он использует JPanel (по умолчанию - вы можете изменить это, вызвав setContentPane()). Что касается того, почему он возвращает Container вместо JPanel - это потому, что вы должны запрограммировать интерфейс, не реализация - на этом уровне все, что вам нужно, это то, что вы можете добавить Component s к чему-то - и даже если Container является классом, а не интерфейсом - он предоставляет интерфейс, необходимый для сделать именно это.

Что касается того, почему и JFrame.add(), и JFrame.getContentPane().add() оба делают одно и то же - JFrame.add() отменяется для вызова JFrame.getContentPane().add(). Это не всегда было так - до JDK 1.5 вам всегда приходилось явно указывать JFrame.getContentPane().add() и JFrame.add() бросать RuntimeException, если вы его вызывали, но из-за множества жалоб это было изменено в JDK 1.5, чтобы делать то, что нужно. вы ожидаете.

3 голосов
/ 12 марта 2010

Хороший вопрос. Мне было полезно понять, что «Swing предоставляет три обычно полезных класса контейнеров верхнего уровня: JFrame, JDialog и JApplet. ... Для удобства метод add и его варианты, remove и setLayout имеют был переопределен для перенаправления на панель содержимого при необходимости. "- Использование контейнеров верхнего уровня

1 голос
/ 25 января 2011

История и механика этого также обсуждаются в некоторых деталях в этой статье leepoint . Обратите внимание, в частности:

getContentPane() возвращает объект Container. Это на самом деле не простой Container объект, но на самом деле JPanel! Это Container как следствие иерархии. Поэтому, если мы получим предопределенную панель содержимого, то получится, что это на самом деле JPanel, но мы действительно не сможем воспользоваться функциональностью, добавленной JComponent.

и

Они определили add() методы в JFrame, которые просто вызывают соответствующие add() методы для панели содержимого. Кажется странным добавлять эту функцию сейчас, тем более что во многих макетах используются несколько вложенных панелей, поэтому вам все равно придется комфортно добавлять непосредственно в JPanel. И не все, что вы хотите сделать с панелью содержимого, можно сделать с помощью вызовов JFrame.

1 голос
/ 23 августа 2010

интересно: jframe.setBackground(color) у меня не работает, но jframe.getContentPane().setBackground(color) работает.

1 голос
/ 12 марта 2010

В последней версии написано API doc , что JFrame.add () (nowerdays) достаточно.

Вы можете сравнить со старыми версиями Java здесь .

1 голос
/ 12 марта 2010

Я полагаю, что причина в том, что Swing был построен из AWT, а Container является объектом AWT верхнего уровня.Это действительно не лучший выбор дизайна, так как вы, как правило, не хотите смешивать объекты AWT (тяжелые) с Swing (легкие).

Я думаю, что лучший способ справиться с этим - всегда приводить contentPane к JPanel.

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