解决GUI编程中图象卡住现象,Swing线程机制
编写GUI界面时,经常会莫名其妙的,画面卡住了,严重的情况甚至黑屏了。为什么会这样呢?
当编写一个Swing程序时,就存在一条Swing事件分发线程(EDT),它区别于main线程。事件分发线程处理所有GUI操作,而它又是一个单一线程,所以就显得非常忙碌(如下图所示)。一旦事件分发线程太忙碌就会出现画面卡住不动的情况。我们在进行Swing编程时,应该把握好以下原则:
1、需要处理的GUI请求非常多,包括窗口移动、组件自动重绘、刷新,它很忙,所以任何与GUI无关的处理不要由EDT来负责
2、职责分明,任何GUI请求都应该在EDT中调用。
一、任何与GUI无关的处理不要由EDT来负责
要达到这种效果的方法有很多,这里只介绍一种,即自己开发一条新的线程来处理与EDT无关的复杂运行,或占用资源时间较长的运算。下面是一个例子,为了顺利播放一个绘制十个圆圈和十个正方形的动画.
下面那样不可以运行,会卡住:
public class Test extends JPanel{
int x=10,y=10,time=10,i=0;
public Test(){
}
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int j=0;j<i;j++){
g.drawOval(100+j*x, 200+j*y, 30, 30);
g.drawRect(200+j*x, 100+j*y, 30, 30);
//EDT运行到这里卡住了,因为Thread.sleep(1000)让它阻塞了一秒钟
try{
Thread.sleep(1000);
}catch(Exception e){}
}
}
public void update(Graphics g){
paint(g);
}
public static void main(String args[]){
JFrame jf= new JFrame();
jf.setBounds(100, 200, 500, 500);
jf.setVisible(true);
Test test = new Test();
jf.add(test);
}
}
程序画一个动画,每隔一秒钟画一个圆和一个正方形,共画十个,但由于程序让EDT每次都阻塞一秒,EDT阻塞就无法正常绘制图象,画面就卡住了。办法是开发另一条线程,用他来“承担”阻塞这个重担,EDT每次只要重绘一下就行了。
开发另一条线程,动画就不卡了
package newpackage;
import javax.swing.*;
import java.awt.Graphics;
public class Test extends JPanel{
int x=10,y=10,time=10,i=0;
public Test(){
}
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int j=0;j<i;j++){
g.drawOval(100+j*x, 200+j*y, 30, 30);
g.drawRect(200+j*x, 100+j*y, 30, 30);
}
}
public void update(Graphics g){
paint(g);
}
public static void main(String args[]){
JFrame jf= new JFrame();
jf.setBounds(100, 200, 500, 500);
jf.setVisible(true);
Test test = new Test();
jf.add(test);
Draw d = new Draw(test);
d.start();
}
}
//定义的另一条线程,Thread.sleep(1000),是让线程阻塞,此动作不能让EDT来做,不然会卡住
class Draw extends Thread{
Test t;
Draw( Test t){
this.t = t;
}
public void run(){
for(;t.i<t.time;t.i++){
t.repaint();
try{
Thread.sleep(1000);
}catch(Exception e){}
}
}
}
二、任何GUI请求都应该在EDT中调用。(下面这一段是从《think in java》中抄来的。)
(待续)