Java paint与paintComponent的区别与联系

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lishang6257/article/details/78089834

在上学期,做了一些简单Java程序,做了一个GUI矩阵运算器,还有像什么基于C/S模式的销售管理系统, 聊天室这种东西,都是些组件做的。但这次准备入手做一些用Graphics绘图做的东西。刚入手就发现了这个问题,Java中paint与paintComponent在使用还是存在很多差异的。先把本文讨论主干问题列上:

1)联系
2)区别
3)在程序中表现出的异同
4)本次test中发现的有趣的问题与现象

〇、背景知识

要说明这个问题,首先要简单了解绘图的原理。Graphics是一个抽象类,在不同平台上运行时,会由系统创建一个Graphics的一个子类 。说到Graphics,也就不得不说JComponent类,他是Java中诸多GUI组件的超类(这里指的Swing包内的组件),其内恰好有个paint(Graphics g)的方法。
当程序进行绘图时,JComponent会调用paint()方法,此时系统会生成Graphics对象,并将引用g传到paint()方法内,接着你就可以通过对g修改来进行绘图;如果运行时g发生改变,需要调用repaint()方法进行重绘,repaint()会首先调用update()方法进行背景的清除,然后再调用paint()方法进行绘制。

注意:Component为AWT包内的GUI组件的超类,其内只包含paint()方法,无paintComponent()方法。[更新于17.9.26]
一、区别与联系【1】

(1)paint() 中调用 paintComponent(), paintBorder(),
paintChildren(),分别用来绘制背景,边框,子控件。 (2)最重要的区别是“双缓冲”。Swing 组件的 paint()
中实现了双缓冲,所以不要随便去覆写,会破坏双缓冲的。 (3)覆写 paint(),如果新方法没有去调用
paintChildren(),还会造成子控件不显示。 (4)只有极少数的情况可能需要覆写 paint()
方法,通常是为了实现特殊的绘图效果,或者特殊的优化

引用:http://bbs.csdn.net/topics/390585720

二、实际中的表现
在此之前需要注意的一点是,不要在JFrame中直接测试,因为在JFrame覆写paint()方法时候完全OK,当覆写paintComponent方法时候,就会无效,这点出现的还没来得及考究,过几天会补充在文后【2】
(1)在JPanel中直接覆写paint()方法

import javax.swing.*;
import java.awt.*;

public class test_graphics extends JPanel {
    public test_graphics(){
        System.out.println("hi,gay");
        setSize(800,600);
        setLocation(200,200);
        setVisible(true);
    }
    //demo 1:
    public void paint(Graphics g){
        super.paint(g);
        System.out.println("paint has been called");
        g.setColor(Color.RED);
        g.drawLine(10,10,200,200);
        g.setColor(Color.GRAY);
        g.drawRect(200,200,100,100);
        g.setColor(Color.magenta);
        g.fillRoundRect(300,300,100,100,50,50);
        g.setColor(Color.blue);
        g.drawRoundRect(400,400,100,100,50,50);
        g.draw3DRect(500,500,100,100,true);
        g.drawOval(200,300,100,100);
        g.fillArc(200,400,100,200,0,100);
    }
    public static void main(String[] args){
        EventQueue.invokeLater(()->{
            JFrame mine = new JFrame();
            mine.setSize(1000,1000);
            mine.setVisible(true);
            mine.add(new test_graphics());
            mine.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        });
    }
}

运行完全没问题 ,不过可以加入JLabel和JButton的测试,会出有时候刷不了的现象,需要鼠标点击后才正常,这边就不做测试了。
有心的童鞋还会发现在绘制时候图形边缘并不光滑,存在诸多锯齿,此时就需要Graphics2D来帮个忙,Graphics2D在SE 1.2 后引入,支持双精度运算,绘制图形更精细,里面的控件可以实现抗锯齿,代码如下

      Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.fillArc(200,500,100,200,0,100);

(2)Jpanel方法内覆写paintComponent()方法

import javax.swing.*;
import java.awt.*;

public class test_graphics extends JPanel {
    public test_graphics(){
        System.out.println("hi,gay");
        setSize(800,600);
        setLocation(200,200);
        setVisible(true);
    }
    //demo2 :
    public void paintComponent(Graphics g){
//        super.paintComponents(g);
        System.out.println("paintComponent is called");
        g.setColor(Color.RED);
        g.drawLine(10,10,200,200);
        g.setColor(Color.GRAY);
        g.drawRect(200,200,100,100);
        g.setColor(Color.magenta);
        g.fillRoundRect(300,300,100,100,50,50);
        g.setColor(Color.blue);
        g.drawRoundRect(400,400,100,100,50,50);
        g.draw3DRect(500,500,100,100,true);
        g.drawOval(200,300,100,100);
        g.fillArc(200,400,100,200,0,100);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.fillArc(200,500,100,200,0,100);
    }
    public static void main(String[] args){
//        EventQueue.invokeLater(()->{
            JFrame mine = new JFrame();
            mine.setSize(1000,1000);
            mine.setVisible(true);
            mine.add(new test_graphics());
            mine.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
//        );
//    }
}

这边需要注意的是,并没有使用时间分配线程,因为在使用时会被调用两次,原因容我仔细研究下线程在来说。

三、心得
突然发现前面出现了一些心得,这边就总结一下:
(1)JFrame中无法直接通过覆写paintComponnet(),这边说的直接,其他方式应该可以实现
(2)直接覆写paint(),可能会出现诸多问题,一个是闪烁,第二是刷新异常,正常只需要覆写paintComponent()即可。
(3)事件分配线程还存在一些问题

—————————分割线(17.9.26)———————————
【2】在这里,找到了关于JFrame为什么不能通过直接覆写paintComponent()方法来实现对背景的更新,原因如下:
JFrame为顶层容器,无法调用JComponent类的内容,所以无法通过覆写paintComponent()实现更新背景;对于JPanel来说,不存在该现象,所以很正常。

猜你喜欢

转载自blog.csdn.net/lishang6257/article/details/78089834