Почему подключение JPanel лучше?

Я только начал кодировать видеоигры и слышал, что делать все ваши рисунки на JPanel и прикреплять эту панель к JFrame лучше, чем просто рисовать на JFrame. Мне просто интересно, почему это лучше?


person kullalok    schedule 09.04.2012    source источник
comment
@mre Это то, что я обычно рекомендую (или близко к этому - см. Мой ответ), но мне также интересно услышать точный источник ОП этой информации. Тому, кто задает вопрос. Это стало бы «хорошим вопросом» с таким небольшим дополнительным объемом информации.   -  person Andrew Thompson    schedule 09.04.2012
comment
+1, один из немногих вопросов по Java, на который я знаю ответ. Создав Java RPG-игру, я получил от нее огромное удовольствие. :)   -  person ApprenticeHacker    schedule 09.04.2012


Ответы (3)


Это лучше по разным причинам, в том числе:

  • В большинстве компонентов Swing пользовательское рисование достигается путем переопределения метода paintComponent(Graphics). Контейнеры Swing верхнего уровня (например, JFrame, JApplet, JWindow) имеют только paint(Graphics). В результате общего метода рисования люди, которые отвечают, часто забывают об этой разнице между общими и высокоуровневыми компонентами и поэтому дают глупые советы. ;)
  • JComponent можно добавить к JFrame, или JApplet, или JDialog, или к ограничению макета в JPanel, или JInternalFrame, или .. Как только вы думаете, что ваш графический интерфейс завершен, клиент говорит: «Привет, не было бы здорово добавить панель инструментов и предложить ее в качестве апплета?» Подход JComponent легко адаптируется к этому.
  • Как объяснил (вместе с кодом!) Риканте, проще вычислить координаты, необходимые для рисования пользовательского компонента, и, если он имеет предпочтительный размер, установить размер JFrame так, чтобы он был «точно подходящего размера», чтобы содержать Графический интерфейс (с использованием pack()). Это особенно актуально, когда добавляются и другие компоненты.

Теперь два небольших несогласия с предложенным советом.

Если весь компонент окрашен вручную, может быть лучше просто поместить BufferedImage в комбинацию ImageIcon/JLabel. Вот пример рисования изображения.
Когда придет время обновить его:

  1. Позвоните getGraphics() для Graphics или createGraphics() для Graphics2D
  2. Нарисуйте пользовательскую картину в этом графическом экземпляре
  3. Избавьтесь от графического экземпляра
  4. Назовите repaint() на этикетке.
person Andrew Thompson    schedule 09.04.2012
comment
Есть некоторое преимущество в получении делегата пользовательского интерфейса панели. - person trashgod; 09.04.2012
comment
@trashgod Спасибо, что напомнили мне. Хотя есть некоторые вещи, которых я не понимаю. 1) Кажется, что пользовательский интерфейс панели получен из JPanel.getUI(), это правильно? 2) Почему JComponent не может (иметь/иметь доступ) к собственному делегату пользовательского интерфейса? 3) Должен ли я начать свой собственный вопрос (ы) по этим вопросам? - person Andrew Thompson; 10.04.2012
comment
JComponent не имеет самого делегата, но предоставляет некоторую базовую инфраструктуру для подклассов, у которых он есть. Как написать собственный компонент Swing. - person trashgod; 10.04.2012
comment
Спасибо, я видел эту статью по ссылке, которую вы разместили в одном из ваших предыдущих ответов (я думал попробовать просмотреть «trashgod + UI + делегат», прежде чем спрашивать;), но не могу сказать, что я (либо внимательно прочитал ее, либо) понял Это. Я посмотрю на это более внимательно. - person Andrew Thompson; 10.04.2012
comment
Нет, я слишком устал и отвлекся, чтобы использовать ваше время с пользой. Я буду продолжать стучать сюда в тот момент, когда я могу позволить себе делать ошибки и тратить время людей, читать документ позже и рассматривать его как вопрос. Спасибо за предложение. :) - person Andrew Thompson; 10.04.2012
comment
Недавно я столкнулся с этим интересным контрпримером, в котором проблема заключалась в JPanel делегате пользовательского интерфейса. Переход на JComponent был решением. - person trashgod; 12.08.2012

Это простой способ сделать двойную буферизацию.

Позвольте мне немного уточнить. В видеоиграх, чтобы избежать мерцания, вызванного перерисовкой, и отобразить более плавную графику, люди обычно используют двойную буферизацию. Они создают закадровую поверхность, рисуют на ней все, а затем отображают всю закадровую поверхность на экране за один раз.

Двойная буферизация

В Java2D и Swing самый простой способ сделать это — просто нарисовать игровой спрайт на JPanel, а затем добавить JPanel в JFrame.

Во-вторых, рисуя вещи на JPanel, вы позволяете отображать больше виджетов GUI и других графических объектов на JFrame без необходимости рисовать их вручную в игровом цикле. Например, кнопки, меню, другие панели, даже другие панели JPanel для рендеринга.

В-третьих, это позволяет вам использовать автоматически переведенные координаты для вашей игры. Вы можете рисовать все от верхнего левого до нижнего правого, не беспокоясь о конкретных вещах оконного менеджера, таких как ширина границ окна, области задач, заголовки и т. д.!

переведенные координаты

Более того, это не просто соглашение, используемое только разработчиками игр на Java. Создание отдельной Game Board, Render Panel или Graphics Widget довольно популярно при программировании игр с использованием библиотеки с внутренним основным циклом, такой как GUI Toolkit. . Вы можете использовать форму пользователя в Windows Forms и доску для рисования в GTK+.

person ApprenticeHacker    schedule 09.04.2012
comment
Рисование изображения на JPanel и последующее добавление JPanel в JFrame не является способом выполнения двойной буферизации. Я почти уверен, что вы можете использовать двойную буферизацию в JFrame. - person Richante; 09.04.2012
comment
@Richante Я очень хорошо знаю, что вы можете удвоить буферизацию в JFrame, я сказал, что использование JPanel - это самый простой способ, а не единственный способ выполнить двойную буферизацию с Java2D и Swing. - person ApprenticeHacker; 09.04.2012
comment
@Richante также, почему это не способ выполнить двойную буферизацию? Он используется довольно часто именно для этой цели. - person ApprenticeHacker; 09.04.2012
comment
Ах да, я не заметил, что JPanel по умолчанию имеет двойную буферизацию. Тогда ты, наверное, прав. - person Richante; 09.04.2012

JFrame включает в себя такие вещи, как меню, строку заголовка и границу. Поэтому, когда вы ссылаетесь на координаты, вы должны учитывать их. Вы также можете добавить в фрейм строку меню или некоторые другие компоненты. Если ваша картина полностью находится в JPanel, то это не изменит того, как вам нужно ссылаться на координаты.

Например, попробуйте:

public class Test extends JFrame {

 public Test() {
   super();
   setVisible(true);
   setBounds(100, 100, 200, 100);
 }

 @Override
 public void paint(Graphics g) {
   g.fillRect(0, 0, 50, 50);
 }

 public static void main(String[] args) {
   new Test();
 }

}

и вы увидите, что черный квадрат не квадрат! Потому что (0, 0) — это верхний левый угол всего кадра, а не угол видимой области.

person Richante    schedule 09.04.2012