from:http://hzylyl.blog.163.com/blog/static/330971642010225059542/
先转了以后看
我们 很多用Java 中的 g.drawImage()方法导入图像时, 如果我们将 当前窗口转变成非当前窗口状态,再从非当前窗口恢复到当前窗口状态,有时,某些绘制 好的图像会消失,除非我们重新刷新窗口,显示才会恢复正常。此外,当我们移动窗口或者其他的窗口在上移动的时候,图像会有些闪烁。这是怎么一回事呢 ?这就要涉及到 Canvas 中的paint 方法的绘图机制了。产生这种现象的主要原因是:
1、由于在显示所绘制的图 像时,调用了 repaint 方 法。 repaint 方法被调 用时,需要清除整个背景,然后才调用 paint 方法显示画面。这样,在清除背景和绘制图像的短暂时间间隔内被用户看见的就是闪烁。
2、由于 paint() 方法需要进行复杂的计算,图像中包含着 多个图形,不同图形的复杂程度及其所需要的绘制时间不同,因此,图像中的各个像素值不能同时产生,使得图形的生成频率低于显示器的刷新频率,从而造成闪 烁。
下面两种方法可以明显地消除或减弱闪烁:
1、重载 update 方法
当AWT 接收到 Canvas 重新绘制的请求时,调用 Canvas 的update 方法。默认情况下, update 方法清除 Canvas 的背景,然后调用paint 方法。重载 update 方法,就可以将以前在 paint 方法中的绘图代码包含在 update 方法中,从而避免每次重新绘制时将整个区 域清除。
2、双缓冲技术
双缓冲技术在很多动画中被采用。主要原理是创建一幅 BufferedImage 图像,将每一帧画入图像,然后调用drawImage 方法,将整个 BufferedImage 图像一次画到屏幕上去。这种方法的优点在于大部分绘制 是在 BufferedImage 进行的。将 BufferedImage 绘制的图像一次绘制到屏幕上。首先通过调用 new BufferedImage 方法生成合适的缓冲区,然后获得在缓冲区的绘图环境(即Graphics 类对象)。
综上所述,我们导入图像的思路是:不直接在paint 方法中调用各种绘制方法,而是采用重载 update 方法及双缓冲技术,生成一个图像的缓冲 区,获得该缓冲区中的绘图环境后,将该绘图环境读入内存。 paint 方法不再负责图像的绘制工作,即 paint 方法不再装入任何的图像绘制代码。我们在 paint 方法中,直接调用 update 方法,在内存缓冲区的绘图环境下进行图像的绘制工作,当所有的图像绘制工作完成后,最后将缓冲区的内容一次性地写入 Canvas 并在窗口中直接显示出来。这种方法很巧妙 地解决了图像丢失和闪烁的问题。
例子代码如下:
package org.lyndon.test;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
public class MyCanvas extends Canvas{
private static final long serialVersionUID =1L;
//窗体的宽与高
public static final int WIDTH =480;
public static final int HEIGHT =480;
private Image screen = createImage ( WIDTH , HEIGHT , true ); //双缓冲
private Graphics graphics = screen .getGraphics();
private Image resultImage ;
/**
*生成一个BufferImage
*生成一个 BufferImageBufferImage是Image的子类,左上角坐标都为(0,0)
*第三个参数是代码Image图形类型,分为14种,以位数又分为1,2或4位
*
* @param width
* @param height
* @param flag
* @return
*/
final static public BufferedImagecreateImage( int width, int height,
boolean flag){
if (flag){
return new BufferedImage(width,height,2);
} else {
return new BufferedImage(width,height,1);
}
}
public MyCanvas(){
//设定初始构造时面板大小
setPreferredSize( new Dimension( WIDTH , HEIGHT ));
//初始导入一张图片
ImageIconicon= new ImageIcon( "image/floor.gif" );
resultImage =icon.getImage();
}
//
@Override
public void update(Graphicsg){
graphics .drawImage( resultImage ,0,0, this );
g.drawImage( screen ,0,0, null ); //最后个参数一定要用null,这样可以防止drawImage调用update方法
g.dispose();
}
public void paint(Graphicsg){
update(g); //我们在paint方法中,直接调用update方法
}
}