您的位置:首页 > 编程语言 > Java开发

关于Java闪屏问题使用双缓存方法解决的方法

2014-10-16 09:36 911 查看
一,Java闪屏出现的原因:

在用java中绘图或者添加图片的时候,使用多线程处理动态问题会出现闪屏的现象,因为AWT先用背景色覆盖组件再重绘图像的方式(即先把屏幕整个清空,然后重绘),而每次重绘都是一个过程,尽管很短但仍需要时间,这就导致了闪烁现象。如果重绘的面积较大的话花去的时间也是比较可观的,这个时间甚至可以大到足以让闪烁严重到让人无法忍受的地步。另外,用paint(Graphics g)函数在屏幕上直接绘图的时候,由于执行的语句比较多,或者创建的线程多导致程序不断地改变窗体中正在被绘制的图象,会造成绘制的缓慢,这也从一定程度上加剧了闪烁。
二,Java闪屏解决的方法:

可以利用双缓冲的手段来解决这个问题。解决思路:既然由于屏幕刷新与屏幕显示之间不能很好的衔接才造成了屏幕闪烁的结果,那么我们可不可以在屏幕显示之前将它所需要显示的下一屏幕内容提起准备好,当需要显示时直接满屏刷新,这样当需要一个屏幕时该屏幕已经被准备好,循环下去就能解决闪屏的问题。要使用双缓冲来提前绘制所需要的显示图像,就需要了解Java重回机制,然后重新相应的代码即可。

在awt中对于窗体画布的重绘其条用顺序是repaint() —>update()—>paint();所以我们只需要重写awt中的upodate()方法来改变其工作方式,跳过清屏动作即可:

awt中upodate()源码:

/**
* 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方法,先将窗体上的图形画在图片对象上,再一次性显示 
 public void update(Graphics g) {
 <span style="white-space:pre">	</span>if(offScreenImage == null) {
  <span style="white-space:pre">		</span> // 截取窗体所在位置的图片 .创建一幅用于双缓冲的、可在屏幕外绘制的图像。
  <span style="white-space:pre">		</span> offScreenImage = this.createImage(1200, 800);
  <span style="white-space:pre">	</span>}
 <span style="white-space:pre">	</span>// 获得截取图片的画布
 <span style="white-space:pre">	</span>Graphics gOffScreen = offScreenImage.getGraphics();
 <span style="white-space:pre">	</span>// 将截下的图片上的画布传给重绘函数,重绘函数只需要在截图的画布上绘制即可,不必在从底层绘制
 <span style="white-space:pre">	</span>paint(gOffScreen);
 <span style="white-space:pre">	</span>//将截下来的图片加载到窗体画布上去,才能达到每次重画的效果
 <span style="white-space:pre">	</span>g.drawImage(offScreenImage, 0, 0, null);
 }


三,示例代码:

我使用多线程的方法实现雪花漫天纷飞的情景,相应代码如下:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Table extends Frame implements ActionListener {
Button start = new Button("开始");
int[] xx = new int[100];
int[] yy = new int[100];
int[] fs1 = new int[100];
Font fs = null;
Image offScreen = null;
public Table() {
super("雪花飞");
setSize(1200, 800);
//setBackground(Color.black);
// setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setLayout(new FlowLayout());
add(start);
start.addActionListener(this);
validate();
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == start)
begin();
}

public void begin() {
for (int i = 0; i < xx.length; i++) {
xx[i] = (int) (1200 * Math.random());
yy[i] = (int) (800 * Math.random());
fs1[i] = (int) (20 * Math.random() + 12);
}
new Thread() {
public void run() {
while (true) {
for (int i = 0; i < xx.length; i++) {
if ((yy[i] > 800) || (yy[i] < 0))
yy[i] = 0;
yy[i]++;}
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.err.println("Thread interrupted");
}
}
}
}.start();
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, 1200, 800);
Image img = new ImageIcon("11.jpg").getImage();
g.drawImage(img, 0, 0, 1200, 800, null);
for (int i = 0; i < xx.length; i++) {
Font fs = new Font("宋体", Font.BOLD, fs1[i]);
g.setColor(Color.white);
g.setFont(fs);
g.drawString("*", xx[i], yy[i]);// 画雪
}
}
/*public void update(Graphics g) {
if(offScreen == null) {offScreen = createImage(1200, 800);}
Graphics gOffScreen = offScreen.getGraphics();
paint(gOffScreen);
g.drawImage(offScreen, 0, 0, null);
}
*/
public static void main(String args[]) {
new Table();
}
}
注意:该代码包含图片11.jpg,仅需要在该文件所在路径创建一个相同的图片即可,这样更能看出效果。

改代码出现闪屏情况,仅需要将代码中注释掉的update()去掉注释即可!

源代码下载:

点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐