长任务下的Swing设计,Thread

通常新手在设计程序的时候习惯在主线程中更新GUI,当计算任务量小的时候问题暴露不明显,但是这始终是一颗埋着的炸弹,总有一天,当你看到程序“卡”住的时候会明白自己设计的是多么糟糕的界面。

如果目前为止你还没遇到过这个问题,那么试着用一下代码运行一下吧:

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.JTextField;


public class SwingTestWithTrouble extends JFrame {
/**

*/
private static final long serialVersionUID = 1L;
private JButton startButton = new JButton("Start");
private JButton endButton = new JButton("End");
private JProgressBar progressBar = new JProgressBar();
private JTextField textField = new JTextField(10);
private boolean flag = false;
private int count = 0;


public SwingTestWithTrouble() {
setLayout(new FlowLayout());
add(startButton);
add(endButton);
add(textField);
add(progressBar);


textField.setEditable(false);


startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (flag == false) {
flag = true;
while (count < 100 && flag == true) {
try {
Thread.sleep(100);// 模拟长任务
count++;
progressBar.setValue(count);
textField.setText("Completed : " + count + "%");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}
}
}
});
endButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
flag = false;
}
});
}




public static void main(String[] args) {
SwingTestWithTrouble swingTest = new SwingTestWithTrouble();
swingTest.setSize(200, 300);
swingTest.setTitle("SwingTest");
swingTest.setVisible(true);
}
}

当你试着运行完以上的代码,看到“卡住”的界面时候,是不是觉得诧异,为什么代码中的GUI的更新部分到最后才得到应用?那么首先我们先得理解,Swing的大部分组件是非线程安全的, 只能用单线程(Swing专门提供了事件派发线程)访问,就是当主线程在干完它所有的活才会来干Swing的线程中要干的事。这就好理解为什么GUI到最后才更新了。

那么是不是只有坐以待毙,当然不是,我们可以在事件发生时用一个新的线程来处理我们的长任务。这里为了规范和安全,用事件派发线程更新组件,用到SwingUtiLities.invokeLater()或SwingUtiLities.invokeAndWait()。


(两者区别:invokeLater是异步方法,在方法还没执行完就返回, 而inovkeAndWait是同步方法,要等方法执行完后再返回.而且在任何线程中调用invokeLater都不会异常,而在事件派发线程中调用inovkeAndWait会抛出异常,  如果在调用线程与invokeLater或inovkeAndWait方法中的线程有顺序关系,可以使用inovkeAndWait,若没有推荐使用invokeLater。因为inovkeAndWait将会带来一个产生死锁的必要条件--等待运行(意思就是调用线程要等到被调线程结束后才能运行)


这里选择SwingUtiLities.invokeLater()。有了思路以后在看一下修改后的代码:

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;




public class SwingTest extends JFrame {
/**

*/
private static final long serialVersionUID = 1L;
private JButton startButton = new JButton("Start");
private JButton endButton = new JButton("End");
private JProgressBar progressBar = new JProgressBar();
private JTextField textField = new JTextField(10);
private boolean flag = false;
private GoThread t = null;
private int count = 0;


public SwingTest() {
setLayout(new FlowLayout());
add(startButton);
add(endButton);
add(textField);
add(progressBar);


textField.setEditable(false);


startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (flag == false && t == null) {
flag = true;
t = new GoThread();//新开一个线程
t.start();
}
}
});
endButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
flag = false;
}
});
}


private class GoThread extends Thread {
public void run() {
while (count < 100 && flag == true) {
try {
Thread.sleep(100);//模拟长任务
count++;
SwingUtilities.invokeLater(new Runnable() {//事件委派组件更新任务
public void run() {
progressBar.setValue(count);
textField.setText("Completed : " + count + "%");
}
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}
}
}


public static void main(String[] args) {
SwingTest swingTest = new SwingTest();
swingTest.setSize(200, 300);
swingTest.setTitle("SwingTest");
swingTest.setVisible(true);
}
}

现在是不是和你想象的一样了呢?

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值