java画图总结之三(常用方法paint,repaint,update)

三,常用方法paint,repaint,update

这个问题的由来是因为,我在编写java小程序,画图的时候,发现我重写了paint(graphics g)方法,而执行的时候调用的是repaint()无参方法。老师说,repaint里面间接调用了paint方法。但是是如何间接调用的呢?repaint方法里面是否new了一个graphics对象呢然后传给paint呢?
首先paint方法,并不仅是JPanel的方法,而是继承自JComponent的方法,该方法说明如下:
/**
     * Invoked by Swing to draw components
     * Applications should not invoke paint directly,
     * but should instead use the repaint method to
     * schedule the component for redrawing.
     *


     * This method actually delegates the work of painting to three
     * protected methods: paintComponent,
     * paintBorder,
     * and paintChildren.  They're called in the order
     * listed to ensure that children appear on top of component itself.
     * Generally speaking, the component and its children should not
     * paint in the insets area allocated to the border. Subclasses can
     * just override this method, as always.  A subclass that just
     * wants to specialize the UI (look and feel) delegate's
     * paint method should just override
     * paintComponent.
     *
     * @param g  the Graphics context in which to paint
     * @see #paintComponent
     * @see #paintBorder
     * @see #paintChildren
     * @see #getComponentGraphics
     * @see #repaint
     */

------------------------------------解释-----------------------------------------------
这个方法是被swing调用来画组件的,应用不应该直接调用paint,而应该调用repaint。paint这个方法实际上代表了三个protected的方法。 *paintComponent,paintBorder,paintChildren.  *里面一次调用者三种方法来确保....(略)
重要的是子类通常要重写这个方法,来定制special特殊的图形组件。

那么为什么不应该直接调用paint而应该调用repaint呢?查了很多资料,有一个说的很简单,直接。(接下来一段几乎全部引用)
-------------------------------------引用-------------------------------------------
http://wenku.baidu.com/link?url=uXdbhvny1uvjCuWhyD-28cfrVg8I65gq3LOEQCP2Dh2d7rsX-7sEBJwdU0HtCHCh__9XtkhSpBiAhkLVfPpuWfR1F00GQTyIaL1NQZYf_X3

调用paint的一般是repaint()或当显示器刷新的时候调用的类似repaint()的类。
 
当对于桌面执行了某类操作,改变了桌面上的图象时,jvm收到界面被调整的信息,此时会调用visible是ture的图形组件的repaint()
方法对界面重绘。 
 
当然,直接重绘或全部重绘是很亏的,一个是用双缓存技术,另一个是只对桌面上显示的部分重绘。双缓存是指在缓存内先模拟重绘过程,只把最后成形的结果传给显示器显示。部分重绘就是指使用repaint(Dimensionarea)及类似的方法,只重绘与需调整的部分相关的界面。幸运的是,目前jdk提供的repaint()并不是傻呼呼的就直接重绘所有组件,已经用了上述两种方法优化过了。所以即使反复调用repaint()也不会有效率的损失。
 
 
repaint()是重要概念,它是在图形线程后追加一段重绘操作,是安全的!是系统真正调用的重绘!所以如果你需要某个部件刷新一下界面,记得调用repaint(),千万不要直接调用paint()!
paint()是提供给用户编程的,往往声明在接口之中,然后用户实现该接口,以拥有重绘的功能。
若要定制某个图形组件的界面,可以重写paint()方法,记得一般习惯这样改写: 
void paint(Graphics g){  
super.paint(g);  
// your code }  
除了paint(),有的组件会有paintBorder()之类的专门用于某个部分重绘的方法,不过一般是 
protected的,在对该类组件扩展的时候可以重写该方法。
  
最后,graphics是一个抽象类,其实现大都是平台相关的,所以不容易自己创建一个graphics实例。一般graphics的实例会由依照你所在的桌面环境给出。Graphics类及其子类Graphics2D提供的只是一些基本绘图方法,比如画直线、曲线什么的。 
所以做一个图形组件的基本思路可以总结为以下过程: 
选择适合的基本图形组件 -> 继承它 -> 重写paint等方法->在需要刷新图形的时候调用repaint等方法!
至于Graphics,先假设它存在,因为真正的Graphics实例只有当程序在jvm上跑的时候才会创建。(这一点上一章说过了) 
 
如果要找最终调用paint的地方的话,一定是通过repaint()方法。因为直接调用paint(),次数少还行,次数多就会导致该图形进程卡在与显示器的交互上,所以一定只有repaint才是可以被调用来重绘的。然而repiant存在的意义并不是绘界面,而是使绘界面操作更安全。 
 
可以看Component的repaint方法的实现,他将触发重绘的源放在AWTEventQueue里,然后等到图形处理的Queue有空的时候,自动拿出源,此时调用paint()。而paint的参数Graphics也只有此时能传给paint!因为Graphics与系统相关性太大,只能是通过JNI用底层代码实现,也就是C++代码创建。所以你要找到Graphics创建不能从jdk代码里找,要去找jvm的源代码(jdk6开源,你可以找找试试),可能会找到一些带有Impl后缀的关于Graphics的实现。 
然后,如果深究paint()在哪调用,我可以说,你所找到的jdk里所有带有paint()的代码段都不是最终paint被调用的地方。因为jdk只允许paint被repaint触发,而repaint到传递Event给AWTEventQueue后,所有的代码都变成系统相关,那么就不能从jdk里找到实现了。
 ----这也解释了,为什么直接调用repaint就可以,而不用给paint传graphics参数。
系统相关的处理,一般是在jdk只声明接口,然后利用反射机制动态创建。一般类名放在系统的环境变量中,然后反射该类,类的实现不同jvm不同。
------------------------------------引用结束---------------------------------------
 引用总结:就是说repaint比paint优化过效率更高,并且是绘图界面操作更安全。。。。。!!!!

说了这么多,好像跟update没什么关系。那么update又是什么呢?
我在查看repaint源代码的时候发现,repaint是Component类的方法,该类中还有paint和update方法,方法的代码实现,你们可去看,这里不再粘贴,而是放上方法说明:
     * Repaints this component.
     *


     * If this component is a lightweight component, this method
     * causes a call to this component's paint
     * method as soon as possible.  Otherwise, this method causes
     * a call to this component's update method as soon
     * as possible.
     *

意思是,重画组件,如果component是轻量级的(看总结一),repaint会调用paint(不是立即,而是as soon as possible尽快,参考引用)如果是重量级的,则会调用update。
如果你直接调用update的话,update也会先判断这个组件是轻量级还是重量级,如果是轻量级,update又会调用repaint由repaint去调用paint。
感觉没说清楚,看了很多文章,源码,解释,说明,总之在写代码的时候直接用paint或者update就是会有问题(例如有人说闪烁,重叠),所以要用更安全,效率更高的repaint。




你可能感兴趣的:(java)