final Button button = new Button(shell, SWT.CENTER);
button.setText("抓取图像");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
final String wsdl = wsdlText.getText();
final String trDate = trDateText.getText();
final String flowId = flowIdText.getText();
final String dest = saveText.getText();
display.asyncExec(new Runnable() {
public void run() {
try {
button.setText("处理中..");
button.setEnabled(false);
Main4Swt.start(wsdl, trDate, flowId, dest, bar, console);
} catch (Exception e1) {
console.setText(ErrorUtil.getError(e1));
} finally {
button.setText("抓取图像");
button.setEnabled(true);
}
}
});
}
});
我把整个button的事件处理代码都放到了display.asyncExec()中,但是运行以上代码还是会引起界面假死!这事让我抓狂
经过反复实践,得出如下实战步骤:
1. new一个Thread先
2. Thread中分三步走:
2.1 syncExec获取参数
2.2 try执行耗时操作
2.3 asyncExec处理后事
经过修改后的代码如下:
final Button button = new Button(shell, SWT.CENTER);
button.setText("抓取图像");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
new Thread() {
String wsdl = null;
String trDate = null;
String flowId = null;
String dest = null;
public void run() {
// [1]获取参数
display.syncExec(new Runnable() {
public void run() {
wsdl = wsdlText.getText();
trDate = trDateText.getText();
flowId = flowIdText.getText();
dest = saveText.getText();
button.setText("处理中..");
button.setEnabled(false);
Swt.setLogText("");
}
});
// [2]处理耗时操作
try {
Main4Swt ms = new Main4Swt();
ms.start(wsdl, trDate, flowId, dest);
} catch (Exception e1) {
Swt.log(ErrorUtil.getError(e1), 2);
}
//[3]处理后事
display.asyncExec(new Runnable() {
public void run() {
button.setText("抓取图像");
button.setEnabled(true);
}
});
}
}.start();
}
});
注意第一段获得参数的代码是放在syncExec中而非asyncExec
这样做的原因是代码[2]必须在代码[1]执行完后(获得参数结束后)才能继续
最后,因为代码断[1]执行速度极快,可以将这段代码放在Thread之外,此时可以脱去syncExec的外套
最后的最后,invalid thread access的原因是你在thread中直接访问ui了组件,要么在thread之外访问,一旦在thread内访问ui, 就需要给上穿上asyncExec。
最后的最后的最后,shell也是ui,所以在thread内弹出一个对话框也要asynExec。
2013-08-24更新
在使用ProgressMonitorDialog的时候,代码要简化许多,但是参数forkable必须设置为true
ProgressMonitorDialog monitorDialog = new ProgressMonitorDialog(studio.getShell());
IRunnableWithProgress runnable = new IRunnableWithProgress() {
public void run(final IProgressMonitor monitor){
try{
monitor.beginTask("xxxx",size);
//handle
monitor.worked(1)
//other UI resources except monitor should be wrapped up with asyncExec
display.asyncExec(new Runnable()){
public void run(){
MessageDialog.open(....)
}
}
}finally{
monitor.done();
}
}
};
try {
// It is recommended that fork is set to true in most cases.
// If fork is set to false, the runnable will run in the UI thread
// and it is the runnable's responsibility to call
// Display.readAndDispatch() to ensure UI responsiveness.
monitorDialog.run(true, true, runnable);
} catch (Throwable e) {
Logger.error(e);
}