在Java中,循环调用repaint()来显示动画效果,是个很自然的方法,
然而这是不可行的。其实Java有一个GUI (AWT) Thread来负责GUI
事件的分发,这个线程接受输入事件,放入事件队列,从该队列
中拿出一个事件分发出去。而这个线程事实上与GUI component
线程[一般是你应用程序的主线程]是绑定的。也就是说如果当前
的线程休眠,事件分发的线程同样会休眠。试想如果如果不这么
做,事件被分发,而当前线程正在休眠,事件就得不到响应,那么
这个事件就会丢失。
下面看看昨天遇到的一个问题:
昨天gyk同学问我一个动画不能显示,而是立即出来最终的画面,
他就使用循环调用repaint()的方法来显示动画效果:
while(condition){
//修改动画的数据
repaint();
}
然而这是不可行的,实际上多个连续的repaint会合并成一个。这样
只用最后一个repaint()会导致update()和paint()被调用。
如果试图休眠一段时间来隔开多个repaint()操作,从而避免多个连续
的repaint()被合并的问题:
while(condition){
//...修改动画的数据
try {
Thread.sleep(100);
} catch(InterruptedException ex) {}
repaint();
}
事实上是不行的,正像上面我们说的:当前线程sleep,GUI事件分发线程同
样也会sleep,这样这些分发事件事实上被冻结而积累在队列中,同样连续的
多个repaint事件仍然会被合并成一个repaint.
许多时候或许我们简单的认为repaint之会立即调用update和paint,正如我
们上面所说的它只是产生一个事件,然后立即返回,实际上是个异步的操作
过程。
那最终怎么改才行呢?
其实可以用一个专门的线程来做这件事。事实如果你不是刚开始写GUI程序的话,
首先就应该想到用这种方法的,这样才能构建出灵敏的界面。难道你让动画放着
而界面的其他事件得不到响应么?例如按钮不好用。
把上面的代码放在线程类中的run方法,你一点开始播放按钮,就开启这个线程:
public void run(){
while(condition){
//...修改动画的数据
try {
Thread.sleep(100);
} catch(InterruptedException ex) {
}
repaint();
}
}