前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >双缓冲原理在Awt和Swing中实现消除闪烁方法总结

双缓冲原理在Awt和Swing中实现消除闪烁方法总结

作者头像
sr
发布2018-08-20 10:16:30
2.1K0
发布2018-08-20 10:16:30
举报
文章被收录于专栏:swag codeswag code

最近在做Java版贪吃蛇的入门项目,过程中遇到窗口闪烁的问题总结。

一、AWT组件开发

1、AWT

AWT是抽象窗口工具箱的缩写,它为编写图形用户界面提供了用户接口,通过这个接口就可以继承很多方法,省去了很多工作。AWT还能使应用程序更好地同用户进行交互。

AWT中的容器是一种特殊的组件,他可以包含其他组件,即可以把组件方法容器中。Container类是用来存放其他组件的Component类的子类,Frame类又是Component的子类。Frame类用于创建具有标题栏和边界的窗口。这里通过继承Frame类来建立自己的界面。

二、Swing界面编程

       随着Java的发展,AWT已经渐渐被淘汰,它已经不能适应发展的需要,不能满足开发功能强大的用户界面的需要。这时Swing出现了,它是建立在AWT之上的组件集,在不同的平台上都能保持组件的界面样式,因此得到了非常广泛的应用。

1、Swing组件库

在Swing组件中有许多种组件,它们被封装在JFC中,下面我们会对每一种组件进行详细介绍。Swing包很多,但平常用到的只有javax.swing.*和javax.swing.event.*这两个包,其他的很少用到。

       1)、JFC结构

JFC是Java的基础类,是Java Foundation Classes的缩写形式,封装了一组用于构建图形用户界面的组件和特性。JFC包含了图形用户界面构建中需要用到的顶级容器(Applet、Dialog、Frame)、普通容器(面板、滚动面板、拆分窗格组件、选项卡插U能给个和工具条等)、特殊容器(InternalFrame、Layeredpane、root pane)、基本组件(button , combo box , list , menu , slider , spinner和textfild)等。

       2)、与AWT的区别

最大的区别在于Swing组件的实现与本地实现无关。Swing组件比AWT组件具有更多的功能。例如在Swing中添加了按钮组件和标签组件,通过继承来更改Swing组件的行为和外观,访问技术等。


在游戏中相应的实现即主要窗体用Frame和JFrame来构建。

1.Frame:重量级组件

2.JFrame:轻量级组件

出现问题:

①.窗体调用repaint()方法时闪烁严重

②.窗体设置双缓冲重绘后,DrawImage()进行缩放图片时会失真,Graphics2D设置抗锯齿属性也会失效

Ps:问题到目前为止还没有很好的处理,可能相应的用JPanel进行绘制会解决问题(暂未尝试!)


在Awt中对于窗体画布的重绘其条用顺序是repaint() —>update()—>paint();

默认的upadate()中自带clearRect()方法,即清屏功能,程序运行时我们调用repaint()方法刷新则会造成屏幕刚清空,又继续重新调用paint()方法往窗体上绘制,则就造成闪烁问题!

代码语言:javascript
复制
    public void update(Graphics g) {     
        if (isShowing()) {     
            if (! (peer instanceof LightweightPeer)) {     
                g.clearRect(0, 0, width, height);     
            }     
            paint(g);     
        }     
}    

所以闪烁问题我们需要重写update()方法来实现双缓冲

代码:(以本人贪吃蛇项目为例)

代码语言:javascript
复制
public void update(Graphics g) {


		// 截取窗体所在位置的图片  
                   if (image == null)
			image = this.createImage(this.getWidth(), this.getHeight());
		// 获得截取图片的画布
		Graphics gre = image.getGraphics();
                // 获取画布的底色并且使用这种颜色填充画布(默认的颜色为黑色) 
		gre.setColor(gre.getColor());
                // 有清除上一步图像的功能,相当于gImage.clearRect(0, 0, WIDTH, HEIGHT) 
		gre.fillRect(0, 0, this.getWidth(), this.getHeight());
		// 将截下的图片上的画布传给重绘函数,重绘函数只需要在截图的画布上绘制即可,不必在从底层绘制     
		paint(gre);
	        //将接下来的图片加载到窗体画布上去,才能考到每次画的效果  
		g.drawImage(image, 0, 0, null);
		

	}

而Swing中内置双缓冲,我们首先从继承体系来看,JFrame->Frame->Window->Container->Component,在Frame中的update()方法是从Container中继承而来的,而JFrame中却重写了update()方法如下:

代码语言:javascript
复制
public void update(Graphics g) {     
    paint(g);     
}   

对比之后会发现直接调用了paint()函数而没有clearRect(),试图不通过清屏来阻止闪烁的发生。这也就是JFrame本身的一种处理方法。

但是我们用JFrame编程并且重新update()实现双缓冲后,窗体一样狂闪不停!原因为何?

下面引用一张图来说明:

repaint()方法在重量级组件的时候会调用update方法,在轻量级组件的时候会调用paint方法

即JFrame根本不会去调用update()方法!

解决方法:在Paint()中直接进行双缓冲操作

代码:

代码语言:javascript
复制
if (image == null)
			 
	// 截取窗体所在位置的图片  
                   if (image == null)
			image = this.createImage(this.getWidth(), this.getHeight());
		// 获得截取图片的画布
		Graphics gre = image.getGraphics();
                // 获取画布的底色并且使用这种颜色填充画布(默认的颜色为黑色) 
		gre.setColor(gre.getColor());
                // 有清除上一步图像的功能,相当于gImage.clearRect(0, 0, WIDTH, HEIGHT) 
		gre.fillRect(0, 0, this.getWidth(), this.getHeight());
		//调用父类的重绘方法,传入的是截取图片上的画布,防止再从最底层来重绘      
		 super.paint(imageG );
		 
		//蛇身
		if (snake != null) {
			snake.drawSnake(imageG );
			snake.scoreView(imageG );
		}
                //墙体
		if (wall != null)
			wall.drawWall(imageG );
                //食物(金币)
		if (food != null)
			food.drawFood(imageG );
		
		
		
               //将接下来的图片加载到窗体画布上去,才能考到每次画的效果  
		 g.drawImage(image, 0, 0, null);
	}

其中最重要的是 super.paint(imageG );

这里必须先调用父类Frame的方法刷新屏幕清理上一次repaint画出的图像。

然后可以创建一个线程让程序每隔一段时间后自动调用repaint()方法;

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-07-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档