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

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

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

  1. Я избавился от контейнеров. Более подробно я добавил кнопки в панель (экземпляр JPanel ), а затем добавил панель в windows (экземпляр 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); } } 

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

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

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

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

Хороший вопрос. Мне было полезно понять, что «Swing предоставляет три общедоступных classа контейнеров верхнего уровня: JDialog , JDialog и JApplet . … Для удобства метод добавления и его варианты, remove и setLayout были переопределены для перехода к contentPane при необходимости ». – Использование контейнеров верхнего уровня

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

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

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

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

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

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

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

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

а также

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

  • Отправка сообщений между двумя объектами JPanel
  • Как я могу складывать / накладывать jPanels в Java?
  • Возможно ли программирование графического интерфейса?
  • JButton ActionListener - обновление GUI только после нажатия JButton
  • Как создать RecyclerView с несколькими типами просмотра?
  • Каковы некоторые из «лучших» кросс-платформенных инструментов C ++ UI сегодня?
  • Анимированная анимация Blackberry
  • Почему этот код Parallel.ForEach заморозит программу?
  • Мероприятия по событиям в саперах
  • JTable Right Align Header
  • Подвижные столбцы со значением с помощью java
  • Давайте будем гением компьютера.