Обеспокоенность по поводу функции JPanel: paintcomponent () - PullRequest
19 голосов
/ 27 марта 2011

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

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

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

И эта строка super.paintComponent(g): я совсем не понимаю.Спасибо за вашу помощь.

Ответы [ 3 ]

51 голосов
/ 27 марта 2011

Базовая структура:

Ключевое слово 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 голосов
/ 27 марта 2011

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

1 голос
/ 27 марта 2011

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

...