在上学期,做了一些简单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]
- paint() 中调用 paintComponent(), paintBorder(),
paintChildren(),分别用来绘制背景,边框,子控件。- 最重要的区别是“双缓冲”。Swing 组件的 paint()
中实现了双缓冲,所以不要随便去覆写,会破坏双缓冲的。- 覆写 paint(),如果新方法没有去调用
paintChildren(),还会造成子控件不显示。- 只有极少数的情况可能需要覆写 paint()
方法,通常是为了实现特殊的绘图效果,或者特殊的优化引用:http://bbs.csdn.net/topics/390585720
在此之前需要注意的一点是,不要在JFrame中直接测试,因为在JFrame覆写paint()方法时候完全OK,当覆写paintComponent方法时候,就会无效,这点出现的还没来得及考究,过几天会补充在文后【2】
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);
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来说,不存在该现象,所以很正常。