关于JPanel功能的担忧:paintcomponent()

时间:2011-03-27 00:35:35

标签: java swing jpanel

你好我是java编程的新手,我需要有人向我解释这些代码行:

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

我不明白行public void paintComponent(Graphics g):为什么我必须声明这个函数,如果它是在JPanel中预定义的?

这一行super.paintComponent(g):我根本不明白。谢谢你的帮助。

3 个答案:

答案 0 :(得分:51)

基本结构:

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对象gGraphics是一个帮助类,允许您在面板上绘制内容,如下所示:

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)paintComponentJPanel类)的超类调用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);
    }
}

答案 1 :(得分:2)

paintComponent()是最初在抽象类JComponent中定义的方法。直接间接扩展JComponent的组件(如果公开)可以选择覆盖paintComponent()。对super.paintComponent(g)的调用调用超类的paintComponent()实现(在你的情况下是JPanel的)。如果你想用paintComponent()做其他事情,除了JPanel已经做过的事情之外你想覆盖Graphics g

答案 2 :(得分:1)

如果要在绘制时更改组件的方式,则只需在类中定义paintComponent()。在您的自定义实现中,您需要调用super.paintComponent(g);,即paintComponent()的基类版本,因为它为绘制组件做了一些必要的工作。