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

Проблемы, связанные с функцией JPanel: paintcomponent()

Привет, я новичок в программировании на Java, и мне нужен кто-то, объясняющий мне эти строки кода:

 public class drawpanel extends JPanel
 {
     public void paintComponent(Graphics g)
     { 
         super.paintComponent(g);
         ...
     }
 }

Я не понимаю строку public void paintComponent(Graphics g): почему я должен объявить эту функцию таким, как если бы она была предопределена в JPanel?

И эта строка super.paintComponent(g): я вообще этого не понимаю. Благодарим вас за помощь.

4b9b3361

Ответ 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);
    }
}

Ответ 2

paintComponent() - это метод, первоначально определенный в абстрактном классе JComponent. Компоненты, которые напрямую расширяют JComponent (если они открыты), имеют возможность переопределить paintComponent(). вызов super.paintComponent(g) вызывает реализацию суперкласса paintComponent() (в вашем случае это JPanel). Вы бы хотели переопределить paintComponent(), если хотите сделать другие вещи с помощью Graphics g, кроме того, что уже делает JPanel.

Ответ 3

Вам нужно только определить paintComponent() в своем классе, если вы хотите изменить способ составления вашего компонента. В вашей пользовательской реализации вам нужно вызвать super.paintComponent(g);, т.е. Версию базового класса paintComponent(), потому что она выполняет некоторую необходимую работу по подготовке компонента для рисования.