1. EDT (Event Dispatch Thread)
Question: Why are GUIs Single-threaded?
1) 不要再EDT执行时间较长的任务,否则GUI无法及时响应。
2) SwingUtilities.invokeLater() 可以将一个Runnable任务调度到事件线程中执行(可以在任意线程中调用)
2. 短时间的GUI任务
在EDT中处理
3. 长时间的GUI任务
使用SwingWorker,支持取消、进度标识和完成标识(可以考虑用于改正以前的假进度条了)。
下面是一个demo,from http://www.java2s.com/Code/Java/JDK-6/SwingWorkerfromJDK6SE.htm
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
public class SwingWorkerDemo {
public static void main(String[] args) {
JTextArea textArea = new JTextArea(10, 20);
final JProgressBar progressBar = new JProgressBar(0, 10);
final CounterTask task = new CounterTask();
task.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer) evt.getNewValue());
}
}
});
JButton startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
task.execute();
}
});
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
task.cancel(true);
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(startButton);
buttonPanel.add(cancelButton);
JPanel cp = new JPanel();
LayoutManager layout = new BoxLayout(cp, BoxLayout.Y_AXIS);
cp.setLayout(layout);
cp.add(buttonPanel);
cp.add(new JScrollPane(textArea));
cp.add(progressBar);
JFrame frame = new JFrame("SwingWorker Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(cp);
frame.pack();
frame.setVisible(true);
}
}
class CounterTask extends SwingWorker<Integer, Integer> {
private static final int DELAY = 1000;
public CounterTask() {
}
@Override
protected Integer doInBackground() throws Exception {
int i = 0;
int count = 10;
while (!isCancelled() && i < count) {
i++;
publish(new Integer[] { i });
setProgress(count * i / count);
Thread.sleep(DELAY);
}
return count;
}
protected void process(List<Integer> chunks) {
System.out.println("process : " + Thread.currentThread().getName());
for (int i : chunks)
System.out.println(i);
}
@Override
protected void done() {
System.out.println("done : " + Thread.currentThread().getName());
if (isCancelled())
System.out.println("Cancelled !");
else
System.out.println("Done !");
}
}
运行结果:
process : AWT-EventQueue-0
1
process : AWT-EventQueue-0
2
process : AWT-EventQueue-0
3
process : AWT-EventQueue-0
4
process : AWT-EventQueue-0
5
process : AWT-EventQueue-0
6
process : AWT-EventQueue-0
7
process : AWT-EventQueue-0
8
process : AWT-EventQueue-0
9
process : AWT-EventQueue-0
10
done : AWT-EventQueue-0
Done !
可以看出,progress(在事件指派线程 上异步地从 publish
方法接收数据块)方法果然是被EDT线程调度的。