Ответ 1
Основная структура:
Ключевое слово extends
означает, что DrawPanel
наследуется от JPanel
. Другими словами, DrawPanel
"является" JPanel
. Таким образом, он может переопределять свои методы (те, которые не отмечены final
). Возможно, вы захотите сделать это по нескольким причинам. Например, вы можете получить доступ к классу Graphics
, который можно использовать для рисования круга на панели или гистограммы или строки текста.
Если вы не переопределите какие-либо методы, то при расширении JPanel
вы получите что-то вроде этого:
public class DrawPanel extends JPanel {
//TODO not much
}
Однако это не очень полезно... если вам просто не нравится имя JPanel
и вы хотите называть его AwesomePanel
(обратите внимание: не делайте этого). Если это все, что вам нужно, вам лучше создать экземпляр JPanel
, например: JPanel drawPanel = new JPanel();
paintComponent:
Цель расширения JPanel
заключается в переопределении метода paintComponent
. JPanel
невидим, пока вы не переопределите paintComponent
(обратите внимание: невидимость делает его полезным контейнером для кнопок и других компонентов). Вы правы в том, что метод paintComponent
предопределен (в классе JComponent
, если вам интересно), но весь этот метод делает пустой JPanel
. Если вы хотите нарисовать что-то на панели, вам необходимо переопределить его, например:
public class DrawPanel extends JPanel {
@Override public void paintComponent(Graphics g) { // <-- HERE!
//TODO draw stuff
}
}
Примечание: часть @Override
не является строго необходимой, но ее целесообразно включить в нее, поскольку она уменьшает количество ошибок времени выполнения и улучшает читаемость кода.
Теперь у вас есть доступ к объекту Graphics
g
для панели. Graphics
- это вспомогательный класс, который позволяет рисовать объекты на панели, например:
public class DrawPanel extends JPanel {
@Override public void paintComponent(Graphics g) {
g.drawOval(50, 50, 50, 50); // <-- draws an oval on the panel
}
}
super.paintComponent:
полезная метафора (которую я только что составил): JPanel
- это холст, объект Graphics
- это ваша кисть, а super.paintComponent(g)
- ваш ластик. (Кроме того, JFrame
- ваш мольберт.)
Итак, super.paintComponent(g)
вызывает метод paintComponent
из суперкласса класса JPanel
(класс JComponent
), чтобы стереть все, что нарисовано в данный момент на панели. Это полезно для анимации.
Например, рассмотрим возможность рисования аналоговых часов на панели. Вы должны обновлять его каждую секунду, поэтому каждую секунду вам нужно стереть предыдущие часы и перерисовать часы, отрегулировав секундную стрелку. Если вы не вызываете super.paintComponent(g)
перед перерисованием часов, он просто будет рисовать новые часы поверх старых часов, а через 60 секунд у вас будет только заполненный круг, более или менее.
Помните только одну вещь: всегда вызывайте super.paintComponent(g)
сначала в методе paintComponent
, например:
public class DrawPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g); // <-- HERE!
g.drawOval(50, 50, 50, 50);
}
}
Что это. Не стесняйтесь обращаться ко мне.
Пример:
Я создал простой пример, который использует эти понятия для отображения строки текста на панели (которая помещается внутри рамки). Сохраните в своей среде IDE TestPanel.java.
import java.awt.*;
import java.util.*;
import javax.swing.*;
/**
* A frame containing a panel that is sometimes red and sometimes
* blue. Also, it displays the word to go with it.
*
* Inspired by www.sometimesredsometimesblue.com.
*
*/
public class TestPanel extends JPanel {
private Random random = new Random();
private boolean isRed;
private String s = "";
public TestPanel() {
//randomly determine whether the background should be red
isRed = random.nextBoolean();
//set the background to blue
setBackground(Color.BLUE);
s = "BLUE";
//if 'isRed' is true, set the background to red
if (isRed) {
setBackground(Color.RED);
s = "RED";
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//write either "RED" or "BLUE" using graphics
g.setColor(Color.WHITE);
g.setFont(new Font("serif", Font.BOLD, 60));
g.drawString(s, getWidth() / 2 - g.getFontMetrics().stringWidth(s) / 2,
getHeight() / 2 + g.getFontMetrics().getHeight() / 2);
}
//main method: create an instance of TestPanel and output it on a JFrame
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(500, 500);
f.setTitle("Sometimes Red, Sometimes Blue");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new TestPanel());
f.setVisible(true);
}
}