Добрый день. Наткнулся на вот такой пример в учебнике:
public class Tester {
public static void main(String[] args) {
Frame frame = new Frame();
frame.start();
}
}
class Frame {
private JFrame frame;
private Paint oval;
private int x,y;
Frame(){
x = y = 120;
frame = new JFrame();
oval = new Paint();
}
public void start() {
frame.getContentPane().add(oval);
frame.setSize(700, 700);
frame.setVisible(true);
for(int count = 0;count <400;count++) {
x++;
y++;
oval.repaint();
try {
Thread.sleep(25);
} catch (Exception ex) {
}
}
}
class Paint extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.ORANGE);
g.fillOval(x,y, 100, 100);
}
}
}
Данный код рисует окружность в окне и используя цикл перерисовывает её, перемещая по диагонали. Так вот, изначально автор не добавлял эти две строки кода:
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
То есть не зарисовывал всё окно белым цветом перед рисованием фигуры на новой позиции. В результате фигура расплывалась. Как по мне это костыль.
Когда я писал этот пример, я в учебник не смотрел, и метод repaint(); вызывал не у класса Paint, а у формы JFrame, у меня сразу всё нормально отображалось. Так вот собственно вопрос, какой из методов вы считаете целесообразней использовать?
Вот мой код:
public class Tester {
public static void main(String[] args) {
Frame frame = new Frame();
frame.start();
}
}
class Frame {
private JFrame frame;
private Paint oval;
private int x,y;
Frame() {
x = y = 120;
frame = new JFrame();
oval = new Paint();
}
public void start() {
frame.getContentPane().add(oval);
frame.setSize(700, 700);
frame.setVisible(true);
for (int count = 0;count <400;count++) {
x++;
y++;
**frame.repaint();**
try {
Thread.sleep(25);
} catch (Exception ex) {
}
}
}
class Paint extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.ORANGE);
g.fillOval(x,y, 100, 100);
}
}
}
Ответ
Вообще ошибка в том, что в переопределённом методе paintComponent необходимо вызвать родительский метод:
public void paintComponent(Graphics g){
super.paintComponent(g); // <<<
g.setColor(Color.ORANGE);
g.fillOval(x,y, 100, 100);
}
Он в частности и очистит фон и тогда вызов oval.repaint() будет работать как положено. Про это хорошо написано в документации к родительскому методу:
Further, if you do not invoke super's implementation you must honor the opaque property, that is if this component is opaque, you must completely fill in the background in a non-opaque color. If you do not honor the opaque property you will likely see visual artifacts.
Что примерно переводится как:
Далее, если вы не вызовете родительскую реализацию, вы должны учесть непрозрачность компонента, а именно, если он непрозрачный, вам необходимо полностью залить фон непрозрачным цветом. Если вы этого не сделаете, вы увидите визуальные артефакты.
Что мы и наблюдаем. Так что либо вызвать super.paintComponent(g), либо залить вручную (как у вас в коде). А как раз замена на frame.repaint() — это костыль, который скрывает истинную проблему и делает лишнюю работу (вам же не нужно перерисовывать всё окошко, нужно только содержимое перерисовать).
Комментариев нет:
Отправить комментарий