public static void showWaitWithProcessBar(final Window
frame, String msg, final Runnable runnable, ProgressBarData
getProgress) {
final JWindow msgFrame = new JWindow(frame);
JProgressBar progressBar = new JProgressBar();
makeMsgFrameWithProcessBar(frame, msgFrame, msg,
progressBar);
Thread myThread = new Thread(new Runnable() {
@Override
public void run() {
RuntimeException e = null;
try {
ExecutorService executor =
Executors.newSingleThreadExecutor();
executor.execute(runnable);
executor.shutdown();
while (!executor.isTerminated()) {
ThreadUtil.sleep(200);
SwingUtilities.invokeLater(new Runnable() {
@Override
public
void run() {
msgFrame.setLocationRelativeTo(frame);
progressBar.setValue(getProgress.getProgress());
progressBar.updateUI();
}
});
}
if ((frame instanceof JDialog) & executor.isTerminated() &
(getProgress.getProgress() == 100 )) {
SwingUtilities.invokeLater(new
Runnable() {
@Override
public void run() {
frame.dispose();
}
});
}
}
catch(RuntimeException exception) {
e = exception;
}
finally {
msgFrame.setVisible(false);
msgFrame.dispose();
frame.repaint();
if(e != null)
throw e;
}
}
});
public static void showWaitWithProcessBar(final Window frame,
String msg, final Runnable runnable, ProgressBarData getProgress)
{
final JWindow msgFrame = new JWindow(frame);
JProgressBar progressBar = new JProgressBar();
makeMsgFrameWithProcessBar(frame, msgFrame, msg,
progressBar);
Thread myThread = new Thread(new Runnable() {
@Override
public void run() {
RuntimeException e = null;
try {
ExecutorService executor =
Executors.newSingleThreadExecutor();
executor.execute(runnable);
executor.shutdown();
while (!executor.isTerminated()) {
ThreadUtil.sleep(200);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
msgFrame.setLocationRelativeTo(frame);
progressBar.setValue(getProgress.getProgress());
progressBar.updateUI();
}
});
}
if ((frame instanceof JDialog) & executor.isTerminated() &
(getProgress.getProgress() == 100 )) {
SwingUtilities.invokeLater(new
Runnable() {
@Override
public
void run() {
frame.dispose();
}
});
}
}
catch(RuntimeException exception) {
e = exception;
}
finally {
msgFrame.setVisible(false);
msgFrame.dispose();
frame.repaint();
if(e != null)
throw e;
}
}
});
对于以上这个Java的代码,函数showWaitWithProcessBar是在Swing组件的actionPerformed函数中调用的,它的参数runnable是一个费时的操作。如何理解这个函数的实现,需要理解Swing的实现机制:Swing是一个单线程执行的,也就是其界面组件的创建绘制更新都是单线程顺序执行的,如果有多个线程都更新界面的话,其结果是不可预知的。一个典型的Swing程序,参与的线程至少有如下几个:主线程,EDT事件分发处理线程,事件捕获线程;事件捕获线程用户不需要参与,它负责捕获各种信号,如鼠标点击,键盘输入等等信号,并且把这些信号送入一个事件队列中,而EDT线程则是从这个队列中取出信号并且找到其相应的处理函数执行之,然后再处理下一个世纪。从中可以看出Swing程序只有一个事件队列,按先进先出处理。
各种Swing组件的ActionPerformed函数其实是在EDT线程中执行的,如果在这些函数中放置了费时的操作,就会导致Swing界面不能及时响应用户的各种输入。另外SwingUtilities.
invokeAndWait(), SwingUtilities. invokeLater()这两个函数的一个共同的作用就是把它们的操作包装成一个事件放入事件队列中,让EDT去执行相关的动作,这样当在其他的线程中,如果需要访问Swing组件时,就需要用到这两个函数。
回到上面代码,由于showWaitWithProcessBar是在swing组件的ActionPerformed函数调用的,所以它的执行是在EDT线程中,由于这个函数传入的参数runnable是一个费时的操作,所以runnable的执行不能在EDT线程中,所以需要生成一个新的线程来运行,这里用线程池Executors.newSingleThreadExecutor来处理,同时还需要有一个线程用来查询这个runnable操作处理的进度,然后更新到Swing的进度条上,所以这里使用new
一个Thread操作new
Thread(new Runnable()来查询处理的进度,并且使用SwingUtilities.invokeLater让进度条的更新操作回到EDT线程中执行。