知识大全 双缓冲原理在awt和swing中实现消除闪烁的方法

Posted

篇首语:识字粗堪供赋役,不须辛苦慕公卿。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 双缓冲原理在awt和swing中实现消除闪烁的方法相关的知识,希望对你有一定的参考价值。

    对于双缓冲的分析是在坦克大战游戏的设计时开始的 由于当时忙于游戏的整体设计 所以对这一个问题没有进行详细的研究 现在就这个问题来谈谈自己的一些看法 分析前提出几个问题     为什么当想屏幕上添加图片之后会有明显的闪烁现象?    在awt中如何实现双缓冲?    如何理解swing内置双缓冲以及比较他与awt中消除闪烁的方法区别在哪里?    首先我们来解答第一个问题     我们在屏幕上自绘图形或者是添加图片都是要通过所在画布的重绘来实现的 因此闪烁的出现必然与重绘机制有着一些关联 在awt中对于窗体画布的重绘其条用顺序是repaint() —>update()—>paint();我们来看看update()的源码 Java代码    /**    * Updates the container   This forwards the update to any ligheight    * ponents that are children of this container   If this method is    * reimplemented super update(g) should be called so that ligheight    * ponents are properly rendered   If a child ponent is entirely    * clipped by the current clipping setting in g update() will not be    * forwarded to that child     *    * @param g the specified Graphics window    * @see    Component#update(Graphics)    */    public void update(Graphics g)     if (isShowing())     if (! (peer instanceof LigheightPeer))     g clearRect( width height);        paint(g);            从这里我们可以清晰的看到 update中有一个清屏的作用 即g clearRect( width height);然后再在下面调用paint(g) 函数进行重绘 因此到这里的话我们可以在一定程度上对底层的重绘机制有一个了解了     现在我们明白了 屏幕上之所以出现闪烁是因为在update()方法内先要哗哗的清空屏幕上原有的东西 然后又哗哗的往上画 所以在我们需要不断重绘的屏幕上出现闪烁是必然的了 哪怕CPU的速度快之又快     通过上述的分析 在awt中我们解决闪烁问题的思路也因该随之产生 即重写update()函数的代码 改变它的工作原理 于是我们引进一段在坦克大战中已经重写了的update()方法 其中通过改变重绘函数paint(g)重绘的画布对象 由窗体的画布变为截取的图片上的画布gImage 这样的话就很大程度上改善这个问题了 具体如下 Java代码    // 重写update方法 先将窗体上的图形画在图片对象上 再一次性显示    public void update(Graphics g)     if (offScreenImage == null)     // 截取窗体所在位置的图片    offScreenImage = this createImage(WIDTH HEIGHT);        // 获得截取图片的画布    Graphics gImage = offScreenImage getGraphics();    // 获取画布的底色并且使用这种颜色填充画布(默认的颜色为黑色)    Color c = Color BLACK;    gImage setColor(c);    gImage fillRect( WIDTH HEIGHT); // 有清除上一步图像的功能 相当于gImage clearRect( WIDTH HEIGHT)    // 将截下的图片上的画布传给重绘函数 重绘函数只需要在截图的画布上绘制即可 不必在从底层绘制    paint(gImage);    //将接下来的图片加载到窗体画布上去 才能考到每次画的效果    g drawImage(offScreenImage null);        其实一言以蔽之就是通过重写update()方法改变重绘函数paint(g)重绘的画布对象g     以上的讨论我们都是在awt中进行 然后大家就想将继承Frame改为JFrame试试 结果一试就傻眼了 屏幕上居然又是哗哗的闪了 真是辛辛苦苦去改变 一下回到解放前 我们不是在update()中实现双缓冲机制了吗?请看下面的一个对比测试     ( )在awt中测试update():    Java代码    // 重写update方法 先将窗体上的图形画在图片对象上 再一次性显示    public void update(Graphics g)     System out println( awt的update()在此 );    if (offScreenImage == null)     // 截取窗体所在位置的图片    看看结果     要是没觉得意外的话就继续往下看    在swing中测试update():    Java代码    // 重写update方法 先将窗体上的图形画在图片对象上 再一次性显示    public void update(Graphics g)     System out println( Swing的update()在此 );    if (offScreenImage == null)     // 截取窗体所在位置的图片 结果是     是不是有点吃惊了 在我没有故意编出这个东西忽悠大伙的前提下我们可以得知 在swing中update()方法并没有像awt的update()那样随时被调用 所以就很好解释为什么该为继承JFrame之后屏幕重绘闪烁了 就是你认为自己改写了update()方法就会解决这个问题是一厢情愿的 系统并不买你的帐 调都没去调用呐!     那么怎么通过其他的方法消除swing中的闪烁问题呢 我们此时再回到出发点 双缓冲的核心就是改变paint(g)中的画布 那么好了 我直接在paint(g)函数里实现不就得了 下面再来看这一段代码   Java代码    public void paint(Graphics g)        // 在重绘函数中实现双缓冲机制    offScreenImage = this createImage(WIDTH HEIGHT);    // 获得截取图片的画布    gImage = offScreenImage getGraphics();    // 获取画布的底色并且使用这种颜色填充画布 如果没有填充效果的画 则会出现拖动的效果    gImage setColor(gImage getColor());    gImage fillRect( WIDTH HEIGHT); // 有清楚上一步图像的功能 相当于gImage clearRect( WIDTH HEIGHT)    // 调用父类的重绘方法 传入的是截取图片上的画布 防止再从最底层来重绘    super paint(gImage);    // 当游戏没有结束的时候绘出对战双方    if (!getGameOver())     // 画出自己的坦克    paintMyTank(gImage);    // 画出自己坦克发射的子弹    paintMyBullet(gImage);    // 画出敌方坦克    paintEnemyTank(gImage);    // 画出敌方坦克发射的子弹    paintEnemyBullet(gImage);        // 画出草地    paintGrass(gImage);    // 画出小河    paintRiver(gImage);    // 画出石头    paintStone(gImage);    // 画出各种道具    paintTool(gImage);    // 将接下来的图片加载到窗体画布上去 才能考到每次画的效果    g drawImage(offScreenImage null);        有一些相似的部分吧 其中最重要的是super paint(gImage)这句 改变画布在这里 消除闪烁也是在这里!!!    下面我们再探讨最后一个问题 即如何理解swing中内置双缓冲 我们首先从继承体系来看 JFrame >Frame >Window >Container >Component 在Frame中的update()方法是从Container中继承而来的 而JFrame中却重写了update()方法如下 Java代码    /**    * Just calls paint(g)   This method was overridden to    * prevent an unnecessary call to clear the background     *    * @param g the Graphics context in which to paint    */    public void update(Graphics g)     paint(g);        与之前的同名方法相比 这里直接调用了paint()函数而没有clearRect() 也就是清屏的方法 这里他试图不通过清屏来阻止闪烁的发生 这也就是JFrame本身的一种处理方法     以上是通过自己对双缓冲的一些理解 其中还有很多问题 希望牛人们能够积极指出来 并且一起讨论这个问题 cha138/Article/program/Java/hx/201311/27043

相关参考

知识大全 AWT和Swing的概述

AWT和Swing的概述  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!    Java基本类  J

知识大全 AWT和SWING的强大竞争者

SWT:AWT和SWING的强大竞争者  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  从Java

知识大全 Linux下java的Swing/AWT程序乱码解决

Linux下java的Swing/AWT程序乱码解决  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 java中的双缓冲技术

  毕业设计有个远程协助功能得到对方的屏幕后老是会闪很是不爽今天用java的双缓冲技术解决了代码如下本类重写了Swing中的JLabel当Label重绘时会默认的调用它的update方法主要用于清除界

知识大全 Visual C++中实现双缓冲的基本原理

VisualC++中实现双缓冲的基本原理  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  双缓冲的

知识大全 delphi 缓冲画图(内存画图)解决画图闪烁问题[2]

  到了mfc里面由于有了封装所有的hdc被隐藏在对象中做为隐藏参数传递(就是DC类的this啦~~)所以我们的关键话题就转变为了怎样得到想要的DC类而已这个过程其实大同小异的在消息响应的过程中WM_

知识大全 delphi 缓冲画图(内存画图)解决画图闪烁问题[1]

  很多朋友在做绘图程序的时候往往出现屏幕不停刷新产生闪烁的问题这里就告诉大家一个解决办法缓冲绘图如果有人是用取反画图解决这个问题那么在画直线的时候容易出现斑点效果不是很好如果是图片很大那么缓冲画图是

知识大全 Java Swing中使用双击事件

小技巧:JavaSwing中使用双击事件  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  直接在J

知识大全 AWT在鼠标滚轮和输入等事件上的支持

AWT在鼠标滚轮和输入等事件上的支持  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  为演示新的A

知识大全 andriod面试题

如何进行ListView性能优化视图缓存等Android中对View的更新有几种方式?多线程和双缓冲的使用情况AndroidIPC及原理Android多线程处理的机制Android为什么要设计大组件之