使用Java实现双缓冲绘图
来源:互联网 发布:伦纳德数据 编辑:程序博客网 时间:2024/04/30 01:14
使用Java实现双缓冲绘图
当我们使用AWT或Swing绘图时,如果绘制的图像刷新太快,会出现屏闪现象,如之前写的俄罗斯方块小游戏,屏闪现象就很明显。虽然这种闪烁不会给程序的效果造成太大的影响,但给程序的使用者造成了些许不便,针对这种现象,我们大都是采取双缓冲的方式来解决的。双缓冲是计算机动画处理中的传统技术,在用其他语言编程时也可以实现。
导致屏闪的原因
拿上一篇文章中的俄罗斯方块来说明。当创建窗体对象后,显示窗口,程序首先自动调用paint(Graphics g)方法,在窗口上绘制方块与积分信息,在绘制方块下落的线程启动后,该线程每隔一定的时间就修改一下窗口中方块的位置,然后调用repaint()方法实现重绘。
在repaint()方法中,会对我们重写的paint(Graphics g)进行调用,而在paint(Graphics g)方法中,首先调用了父类的paint()方法(不调用则在不同时刻绘制的方块会重叠在一起形成一条线),而父类paint()方法实现了对组件的清除,即用背景色填充整个窗体,然后会继续调用重写paint()方法中后继语句实现方块绘制。这样,我们就看到了一个在新的位置绘制的方块,前面的方块都被背景色覆盖掉了,这就一帧一帧切换显示,就实现了运动的动画效果。
正是这种用背景色填充组件再重绘图像导致了闪烁。在两次看到处于不同位置方块的中间时刻,存在一个在短时间内被绘制出来的空白画面(即用背景色填充组件)。但即使时间很短,如果重绘的面积较大的话花去的时间也是很大的,这个时间甚至可以大到足以让闪烁严重到让人无法忍受的地步。
我们知道了产生闪烁的原因,那么就可以有针对性的来解决问题,使用双缓冲是处理这类问题的传统技术。
双缓冲原理
先在内存中分配一个和我们动画窗口一样大的空间(缓冲区),然后利用getGraphics()方法去获得双缓冲画笔,接着利用双缓冲画笔在缓冲区中绘制我们想要的东西,最后将缓冲区一次性的绘制到窗体中显示出来,这样在我门的动画窗口上面显示出来的图像就非常流畅了。
在swing中,组件本身就提供了双缓冲的功能,我们只需要进行简单的方法调用就可以实现组件的双缓冲(重写组件的paintComponent()方法),在awt中却没有提供此功能。
示例
先创建图像缓冲区:
// 图像缓冲区private Image image;
在缓冲区中绘制出要显示到窗口中的内容:
/** * 绘制图形缓冲区内容 */private void drawBufferedImage() { // 创建缓冲区对象 image = createImage(this.getWidth(), this.getHeight()); // 获取图像上下文对象 Graphics g = image.getGraphics(); g.setColor(getBackground()); g.fillRect(0, 0, image.getWidth(null), image.getHeight(null)); /* 绘制缓冲区内容 */ // 绘制方块 for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { if (map[i][j] == State.ACTIVE) { // 绘制活动块 g.setColor(activeColor); g.fillRoundRect(j * BLOCK_SIZE, i * BLOCK_SIZE + 25, BLOCK_SIZE - 1, BLOCK_SIZE - 1, BLOCK_SIZE / 5, BLOCK_SIZE / 5); } else if (map[i][j] == State.STOPED) { // 绘制静止块 g.setColor(stopedColor); g.fillRoundRect(j * BLOCK_SIZE, i * BLOCK_SIZE + 25, BLOCK_SIZE - 1, BLOCK_SIZE - 1, BLOCK_SIZE / 5, BLOCK_SIZE / 5); } } } /* 打印得分 */ g.setColor(scoreColor); g.setFont(new Font("Times New Roman", Font.BOLD, 30)); g.drawString("SCORE : " + totalScore, 5, 70); // 游戏结束,打印结束字符串 if (!isGoingOn) { g.setColor(Color.RED); g.setFont(new Font("Times New Roman", Font.BOLD, 40)); g.drawString("GAME OVER !", this.getWidth() / 2 - 140, this.getHeight() / 2); }}
在paint()方法中调用:
/** * 将图像缓冲区内容绘制到窗体中 */@Overridepublic void paint(Graphics g) { drawBufferedImage(); g.drawImage(image, 0, 0, this);}
其它代码基本不变。
运行效果:
完整源码:http://download.csdn.net/download/zhliro/8709373
- 使用Java实现双缓冲绘图
- VC 绘图,使用双缓冲技术实现
- VC 绘图,使用双缓冲技术实现
- VC 绘图,使用双缓冲技术实现
- VC 绘图,使用双缓冲技术实现
- VC 绘图,使用双缓冲技术实现
- VC 绘图,使用双缓冲技术实现
- VC 绘图,使用双缓冲技术实现
- VC 绘图,使用双缓冲技术实现
- 双缓冲实现无闪烁绘图
- 图形编辑器之双缓冲实现绘图
- java Applet绘图(涉及双缓冲)
- 双缓冲解决Java绘图严重闪烁
- 内存绘图、双缓冲绘图
- 内存绘图、双缓冲绘图
- Delphi中在TForm绘图时使用DoubleBuffered实现双缓冲的副作用
- VC 绘图,使用双缓冲技术实现 2012-02-06 16:47:07 分类: C/C++
- 双缓冲绘图
- ZigZag Conversion
- C标签-----JSTL获取list的大小
- 深入理解事务--事务ACID特性及隔离级别
- 个人PHP学习笔记(二)--语句结构
- Rcurl抓取NCBI信息
- 使用Java实现双缓冲绘图
- Remove Linked List Elements
- [LeetCode] Add and Search Word - Data structure design
- LeetCode解题报告--Longest Palindromic Substring
- 1005. 7.2 Printing distinct numbers
- Android 判断手机是否联网时异常闪退
- 威威猫系列故事——打地鼠(HDU-4540)
- Triangle -- leetcode
- Cocosd-x(3.4版本)移植Android平台