参考:http://blog.csdn.net/kai_wei_zhang/article/details/8120382
http://www.cnblogs.com/S-E-P/archive/2010/01/27/2045076.html
一、闪烁的原因
动画就是一帧一帧的切换图片。
每次切换都会先用背景色覆盖组件再重绘图像,如此就造成了两帧之间的空白画面。从而导致了闪烁。
注意,这个repaint()函数是从Frame类继承而来的。它先调用update(Graphics g)函数,update(Graphics g)再调用paint(Graphics g)函数
二、解决方案
背景色覆盖、绘图都在内存中进行,最后一次性画到控件上。
也就是我们所说的双缓冲技术。
Frame (收集自网络未实验)
Image ImageBuffer = null;
Graphics GraImage = null;
public void update(Graphics g){ //覆盖update方法,截取默认的调用过程
ImageBuffer = createImage(this.getWidth(), this.getHeight()); //创建图形缓冲区
GraImage = ImageBuffer.getGraphics(); //获取图形缓冲区的图形上下文
paint(GraImage); //用paint方法中编写的绘图过程对图形缓冲区绘图
GraImage.dispose(); //释放图形上下文资源
g.drawImage(ImageBuffer, 0, 0, this); //将图形缓冲区绘制到屏幕上
}
public void paint(Graphics g){ //在paint方法中实现绘图过程
g.drawLine(0, 0, 100, 100);
}
JFrame
在这里说一下,上面所说的不知为啥,我的Update总是 不能调用,怀疑JDK版本更新后,update调用被改变了。
参考自网上
private Image iBuffer;
public void paint(Graphics scr) {
if (iBuffer == null)
iBuffer = createImage(this.getSize().width, this.getSize().height);
Graphics gBuffer = iBuffer.getGraphics();
gBuffer.setColor(getBackground());
gBuffer.fillRect(0, 0, this.getSize().width, this.getSize().height);
gBuffer.setColor(Color.RED);
gBuffer.fillOval(90, ypos, 80, 80);
scr.drawImage(iBuffer, 0, 0, this);
}
例子:实现透明窗体动画效果(好像Swing自带双缓冲技术)。
但是如果在动画上方添加动态String,会失败。
public class Test5 extends JFrame {
private int nowFrame; //当前帧
private Timer timer; //定时器每隔几秒换张图
private Image iBuffer = null; //在内存中创建一个图对象
private Image[] img;
public Test5() {
Toolkit toolkit=getToolkit();
for(int i=0;i<img.length;i++){
img[i]=toolkit.getImage("tupian" + i + ".gif");
}
this.setAlwaysOnTop(true);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
this.setIconImage(SoftIcons.ICON_IMG);
// 设置窗体透明
this.setUndecorated(true);
this.setBackground(new Color(0, 0, 0,0));// alpha分量为零
//每隔0.1秒重绘一次窗口
this.timer = new Timer(100, null);
timer.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
}
@Override
public void paint(Graphics g) {
super.paint(g);
gBuffer.drawImage(img[nowFrame],30,100, null);
if (nowFrame == icons.DANCE_IMG.length - 1) {
nowFrame = 1;
}
}
public static void main(String[] args) {
new Test5();
}
}
改进之后,可以在动画上方添加动态String,窗口透明
public class Test extends JFrame {
private Timer timer;
private myPanel panel;
public Test() {
panel = new myPanel();
// 设置窗体透明
this.setUndecorated(true);
this.setBackground(new Color(0, 0, 0,0));// alpha分量为零
// 设置窗体永远在前
this.setAlwaysOnTop(true);
this.setContentPane(panel);
this.setSize(300, 400);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setIconImage(SoftIcons.ICON_IMG);
this.setVisible(true);
this.timer = new Timer(100, null);
timer.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
panel.repaint();
}
});
timer.start();
}
public static void main(String[] args) {
new Test();
}
class myPanel extends JPanel{
private int nowFrame; //当前帧
private int behavior;
private Image[] img;
private String[] word;
public myPanel() {
this.setOpaque(false);
}
@Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
g.drawString(word[behavior++], 20, 20);
g.drawImage(img[nowFrame++],0,50, null);
if (nowFrame == img.length - 1)
nowFrame = 0;
if (behavior == word.length - 1)
behavior = 0;
}
}
}
因为大部分绘图过程是在内存中进行,所以有效地消除了闪烁。这应用了“以空间换取时间”和“功能分块”的思想