关于JPanel函数的关注点:paintcomponent()

Posted

技术标签:

【中文标题】关于JPanel函数的关注点:paintcomponent()【英文标题】:Concerns about the function of JPanel: paintcomponent() 【发布时间】:2011-07-23 17:10:27 【问题描述】:

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

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

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

还有这行super.paintComponent(g):我完全看不懂。感谢您的帮助。

【问题讨论】:

请阅读基本的 Java 教程,如果您不知道其实际含义,则不应覆盖方法。 @om-nom-nom 当心:答案很广泛,但有一个重要缺陷.. @kleopatra 感谢您的更正 paintComponent由paint()方法调用的update调用。 【参考方案1】:

基本结构:

extends 关键字表示DrawPanel 继承自JPanel。换句话说,DrawPanel“是”JPanel。因此,它可以覆盖其方法(未标记为final 的方法)。您可能出于多种原因想要这样做。例如,您可能想要访问面板的Graphics 类,您可以使用它在面板上绘制一个圆圈、条形图或一串文本。

如果你不覆盖任何方法,那么当你扩展 JPanel 时,你会得到这样的结果:

public class DrawPanel extends JPanel 
    //TODO not much

但是,这并不是很有用...除非您只是不喜欢 JPanel 这个名字而想改名为 AwesomePanel注意:不要那样做)。如果你只有这些,你最好创建一个JPanel实例,像这样:JPanel drawPanel = new JPanel();


油漆组件:

扩展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.paint组件:

有用的比喻(我刚刚编造的): JPanel 是画布, Graphics 对象是你的画笔,并且 em> super.paintComponent(g) 是你的橡皮擦。 (另外, JFrame 是你的画架。)

所以super.paintComponent(g)JPanelJComponent 类)的超类调用paintComponent 方法来擦除当前在面板上绘制的任何内容。 这对动画很有用。

例如,考虑在面板上绘制一个模拟时钟。你需要每秒刷新一次,所以每一秒你都必须擦除前一个时钟并重新绘制时钟,调整秒针。如果您在重绘时钟之前不调用super.paintComponent(g),它将继续在旧时钟之上绘制新时钟,并且在 60 秒内您将拥有的只是一个填充的圆圈,或多或少。

还需要记住一件事:始终在 paintComponent 方法中首先调用 super.paintComponent(g),如下所示:

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 a) 不可见是错误的 b) 子类必须保证遵守他们的合同不透明度:如果不透明(默认),他们必须用完全不透明的颜色填充整个内容区域,如果为假,他们是免费的不填充整个区域。 super.paintComponent 是遵守合同的最简单方法(或者,您可以手动填充它,具体取决于不透明度设置)。无条件仅填充任意部分(如您在标题为 paintComponent 的段落中的)的覆盖是 invalid 很棒的解释 TheBlackKeys!这让我明白了很多【参考方案2】:

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

【讨论】:

但是paintcomponent() 在这些行中实际上做了什么???你能给我一些教程的链接,以便我知道如何使用它。 @jose 你的paintComponent() 正在注意或者至少除了调用基类的paintComponent() 之外没有显示任何内容。调用 super.paintComponent(g) 后,您可以做其他事情;例如g.drawString("hello world!", 10 ,10 ); mmm soo 如果我不调用超类paintcomponent() 那么我不能对图形进行更改,比如画一条线或任何形状?? 你知道任何链接或书籍可以从一开始就帮助我处理java图形吗??? 超类的paintComponent() 可以绘制面板,在大多数情况下您可能不想跳过调用它。您应该在调用 super.paintComponent(g) 之后添加逻辑以绘制您需要的任何内容。【参考方案3】:

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

【讨论】:

以上是关于关于JPanel函数的关注点:paintcomponent()的主要内容,如果未能解决你的问题,请参考以下文章

关于Jpanel中g.drawImage函数bug调试。。。

获得对 JPanel 的关注

关于Swing中JFrame或JPanel重写paint()方法后再在JFrame或JPanel中添加其他组件出现按钮等组件消失不见只有当鼠标扫过时才会出现的问题

JAVA、GUI JPanel、JFrame、paintComponent、图形

关于java JPanel 里面 add (字符串,组件)

单击jPanel(Java)时如何调用函数?