Подтвердить что ты не робот

Какова связь между ContentPane и JPanel?

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

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

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

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

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

  • Почему у нас есть два конкурирующих механизма для выполнения одних и тех же вещей?

  • В чем причина использования контейнеров в комбинации с панелями (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);
    }
}

И в этом примере я использую только 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);
    }
}

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

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

и

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