`
Chang0501
  • 浏览: 24120 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

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

阅读更多

对于双缓冲的分析是在坦克大战游戏的设计时开始的,由于当时忙于游戏的整体设计,所以对这一个问题没有进行详细的研究,现在就这个问题来谈谈自己的一些看法。

 

分析前提出几个问题:

1、为什么当想屏幕上添加图片之后会有明显的闪烁现象?

2、在awt中如何实现双缓冲?

3、如何理解swing内置双缓冲以及比较他与awt中消除闪烁的方法区别在哪里?

 

首先我们来解答第一个问题:

我们在屏幕上自绘图形或者是添加图片都是要通过所在画布的重绘来实现的,因此闪烁的出现必然与重绘机制有着一些关联。在awt中对于窗体画布的重绘其条用顺序是repaint() —>update()—>paint();我们来看看update()的源码:

 

/** 
     * Updates the container.  This forwards the update to any lightweight
     * components that are children of this container.  If this method is
     * reimplemented, super.update(g) should be called so that lightweight
     * components are properly rendered.  If a child component 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 LightweightPeer)) {
                g.clearRect(0, 0, width, height);
            }
            paint(g);
        }
}

 

从这里我们可以清晰的看到,update中有一个清屏的作用,即g.clearRect(0, 0, width, height);然后再在下面调用paint(g),函数进行重绘。因此到这里的话我们可以在一定程度上对底层的重绘机制有一个了解了。

 

现在我们明白了,屏幕上之所以出现闪烁是因为在update()方法内先要哗哗的清空屏幕上原有的东西,然后又哗哗的往上画,所以在我们需要不断重绘的屏幕上出现闪烁是必然的了,哪怕CPU的速度快之又快。

 

 

通过上述的分析,在awt中我们解决闪烁问题的思路也因该随之产生,即重写update()函数的代码,改变它的工作原理。于是我们引进一段在坦克大战中已经重写了的update()方法。其中通过改变重绘函数paint(g)重绘的画布对象,由窗体的画布变为截取的图片上的画布gImage,这样的话就很大程度上改善这个问题了。具体如下

 

// 重写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(0, 0, WIDTH, HEIGHT); // 有清除上一步图像的功能,相当于gImage.clearRect(0, 0, WIDTH, HEIGHT)
		// 将截下的图片上的画布传给重绘函数,重绘函数只需要在截图的画布上绘制即可,不必在从底层绘制
		paint(gImage);
	    //将接下来的图片加载到窗体画布上去,才能考到每次画的效果
		g.drawImage(offScreenImage, 0, 0, null);
	}

 

其实一言以蔽之就是通过重写update()方法改变重绘函数paint(g)重绘的画布对象g。

 

 

以上的讨论我们都是在awt中进行,然后大家就想将继承Frame改为JFrame试试,结果一试就傻眼了,屏幕上居然又是哗哗的闪了,真是辛辛苦苦去改变,一下回到解放前,我们不是在update()中实现双缓冲机制了吗?请看下面的一个对比测试:

 

(1)在awt中测试update():

// 重写update方法,先将窗体上的图形画在图片对象上,再一次性显示
	public void update(Graphics g) {
		
		System.out.println("awt的update()在此...");
		
		if (offScreenImage == null) {
			// 截取窗体所在位置的图片

 看看结果:


 

要是没觉得意外的话就继续往下看

在swing中测试update():

 

// 重写update方法,先将窗体上的图形画在图片对象上,再一次性显示
	public void update(Graphics g) {
		
		System.out.println("Swing的update()在此...");
		
		if (offScreenImage == null) {
			// 截取窗体所在位置的图片

 

结果是:

 
 

是不是有点吃惊了,在我没有故意编出这个东西忽悠大伙的前提下我们可以得知,在swingupdate()方法并没有像awtupdate()那样随时被调用,所以就很好解释为什么该为继承JFrame之后屏幕重绘闪烁了。就是你认为自己改写了update()方法就会解决这个问题是一厢情愿的,系统并不买你的帐,调都没去调用呐!

 

那么怎么通过其他的方法消除swing中的闪烁问题呢,我们此时再回到出发点,双缓冲的核心就是改变paint(g)中的画布,那么好了,我直接在paint(g)函数里实现不就得了,下面再来看这一段代码:

 

public void paint(Graphics g) {
		// 在重绘函数中实现双缓冲机制
		offScreenImage = this.createImage(WIDTH, HEIGHT);
		// 获得截取图片的画布
		gImage = offScreenImage.getGraphics();
		// 获取画布的底色并且使用这种颜色填充画布,如果没有填充效果的画,则会出现拖动的效果
		gImage.setColor(gImage.getColor());
		gImage.fillRect(0, 0, WIDTH, HEIGHT); // 有清楚上一步图像的功能,相当于gImage.clearRect(0, 0, 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, 0, 0, null);
	}

有一些相似的部分吧,其中最重要的是super.paint(gImage)这句,改变画布在这里,消除闪烁也是在这里!!!

下面我们再探讨最后一个问题,即如何理解swing中内置双缓冲,我们首先从继承体系来看,JFrame->Frame->Window->Container->Component,在Frame中的update()方法是从Container中继承而来的,而JFrame中却重写了update()方法如下

    /** 
     * Just calls <code>paint(g)</code>.  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本身的一种处理方法。

 

以上是通过自己对双缓冲的一些理解,其中还有很多问题,希望牛人们能够积极指出来,并且一起讨论这个问题。

 

 

  • 大小: 32.5 KB
  • 大小: 10.5 KB
6
14
分享到:
评论
2 楼 JuliaAilse 2011-10-21  
羡慕的说!!!我要加油努力了!
1 楼 Coco_young 2011-05-04  
相当给力

相关推荐

    Java双缓冲技术原理详细讲解例子

    Java双缓冲技术是一种提高图形界面性能的...在Swing中,通过重写`paintComponent()`方法并调用`super.paintComponent(g)`可以轻松实现双缓冲。理解并掌握双缓冲技术对于提升Java图形界面应用的性能和用户体验至关重要。

    双缓冲区绘制线条,避免绘图闪烁

    在计算机图形学中,双缓冲区技术是一种常用于优化图形绘制和更新,特别是对于动态图形显示,以消除或减少屏幕闪烁现象的策略。这个技术在游戏开发、GUI(图形用户界面)设计以及动画制作等领域中广泛应用。下面我们...

    利用双缓冲的方法解决界面屏闪

    双缓冲是一种优化图形绘制的方法,尤其在GUI(图形用户界面)和游戏开发中广泛应用。 双缓冲的基本原理是创建两个帧缓冲区,一个是后台缓冲区,一个是前台缓冲区。在后台缓冲区中,所有的绘图操作首先在这里完成,...

    利用双缓冲做的时钟程序

    总的来说,这个时钟程序运用了Java的GUI库,特别是AWT和Swing,通过双缓冲技术解决了屏幕闪烁问题,实现了平滑、无干扰的时间显示。源码文件`Date00.java`包含了实现这一功能的关键代码,而其他文件可能是程序的辅助...

    俄罗斯方块_带双缓冲绘图

    在计算机图形学中,双缓冲技术是一种优化图形绘制的方法,特别是在动态游戏或者实时渲染场景中,它可以显著减少图像闪烁,提高用户体验。本篇文章将深入探讨如何使用Java语言来实现一个带双缓冲绘图的俄罗斯方块游戏...

    java画图(双缓冲)

    在Java中,我们可以使用Java AWT或Swing库来实现双缓冲。Swing提供了`JComponent`类,它支持自定义组件并允许我们重写`paintComponent(Graphics g)`方法进行绘图。在这个方法中,我们可以先在一个`Graphics2D`对象上...

    双缓冲方法解决屏幕刷新闪烁的问题(rar)

    在Java、C++、Python等编程语言中都有相应的库支持实现双缓冲,例如Java的AWT和Swing库,C++的OpenGL库,以及Python的Pygame库等。 总结起来,双缓冲是一种优化图形显示质量的技术,通过分离绘制和显示过程,有效...

    双缓冲范例之水扁跳舞

    在计算机图形学和游戏开发领域,"双缓冲范例之水扁跳舞"是一个生动的示例,用于演示如何利用双缓冲技术来优化图形渲染并消除屏幕闪烁现象,从而提高用户体验。双缓冲是一种重要的图形绘制策略,尤其在动态图像如动画...

    商业编程-源码-实例解说双缓冲.zip

    在实际编程中,双缓冲的实现通常依赖于特定的图形库或API,如DirectX、OpenGL或Java的AWT/Swing库。下面是一个简单的双缓冲概念的步骤: 1. **创建双缓冲画布**:首先,你需要创建两个缓冲区,一个用于绘制,一个...

    DrawPanel双缓冲实现画板

    而双缓冲的工作原理是先在一个内存中的“缓冲区”绘制整个画面,然后再一次性地将这个完整的缓冲区内容复制到屏幕上。这种方法确保了画布的完整性和流畅性,提高了用户体验。 在Java中实现`DrawPanel`的双缓冲,...

    使用双缓冲绘画.rar .

    例如,在Java的Swing或AWT库中,可以创建一个`BufferStrategy`对象来实现双缓冲。以下是一个简单的Java示例: ```java // 创建组件 JFrame frame = new JFrame("双缓冲示例"); frame.setSize(800, 600); frame....

    利用双缓冲做的时钟程序1 .rar_双缓冲

    双缓冲的工作原理是,在内存中创建一个额外的缓冲区,用于绘制所有图像变化。在这个"后台缓冲区"中,开发者可以自由地进行多次绘制操作而不会影响到屏幕上已经显示的内容。当所有的绘制工作完成后,一次性将后台缓冲...

    双缓冲绘图实例.zip

    在Java中,我们可以使用`java.awt.Graphics2D`类和`javax.swing.JComponent`来实现双缓冲。在这个实例中,`DoubleBuffering.java`文件很可能是包含主类或关键绘图逻辑的源代码。`DoubleBuffering.class`是编译后的...

    JAVA双缓冲绘图源码

    本文将深入探讨Java中的双缓冲绘图,以及如何在AWT窗体上实现这一技术。 双缓冲是一种优化图形绘制的技术,它通过在内存中创建一个临时的“缓冲区”,在这个缓冲区中完成所有的绘图操作,然后再一次性将整个缓冲区...

    java双缓冲技术————包含实例及技术详解,适合新手

    在Java中,双缓冲技术主要应用于Swing和AWT组件的绘制过程中,尤其是当需要频繁更新显示内容时。 ##### 1. 单缓冲与双缓冲的区别 - **单缓冲**:直接在屏幕上绘制图像,每次绘制都会覆盖之前的图像,如果绘制过程...

    11 双缓冲技术.ppt

    双缓冲技术是计算机图形学中的一种优化策略,主要用于提高图形界面的显示质量,避免闪烁和撕裂现象。在Java编程中,尤其是在开发图形用户界面(GUI)或游戏时,双缓冲技术尤其重要。 在Java中,图形绘制主要通过...

    如何用java编写小游戏.doc

    java编写小游戏基础知识 ...使用Java编写小游戏需要了解AWT和Swing的使用、双缓冲技术、游戏编程的基本步骤和游戏逻辑的实现。通过本文,我们可以掌握Java编写小游戏的基础知识,并开始编写自己的小游戏。

    基于Timer的最简单的双缓冲画图实例教程

    在计算机图形学中,双缓冲绘图是一种优化技术,用于减少屏幕闪烁和图像撕裂现象。这种方法主要应用于GUI(图形用户界面)和游戏开发中,确保连续、平滑的动画效果。本教程将深入讲解如何利用Java的Timer类实现一个...

    Java Swing 线程 下雪效果

    可能需要使用缓存策略,例如只更新移动的雪花,或者使用双缓冲技术来减少闪烁。 通过以上步骤,我们可以在Java Swing中实现一个逼真的下雪效果,同时保持UI的响应性和线程的安全性。这种技能对于开发互动性强、视觉...

    JAVA人物动画.rar_JAVA画人像_java人物动画_动漫人物java_双缓冲

    在这个名为"JAVA人物动画.rar"的压缩包中,我们重点探讨的是如何利用Java来实现生动的人物动画,特别是针对"java画人像"、"java人物动画"、"动漫人物java"和"双缓冲"这些标签所涉及的技术。 首先,让我们深入理解...

Global site tag (gtag.js) - Google Analytics