我有一个Eclipse RCP应用程序。当执行某个命令时,需要启动一个线程。线程执行完毕后,必须更新GUI。但是我认为此线程或其他非SWT线程无法更新GUI,尽管这似乎合理。当我尝试这样做时,我遇到了Exception in thread "Thread-5" org.eclipse.swt.SWTException: Invalid thread access
错误。我如何实现这个目标?
我有一个Eclipse RCP应用程序。当执行某个命令时,需要启动一个线程。线程执行完毕后,必须更新GUI。但是我认为此线程或其他非SWT线程无法更新GUI,尽管这似乎合理。当我尝试这样做时,我遇到了Exception in thread "Thread-5" org.eclipse.swt.SWTException: Invalid thread access
错误。我如何实现这个目标?
使用SWT时,需要确保所有更新GUI的操作必须在主线程中完成,在Eclipse中,它被称为UI线程(它是同一个线程)。如果你尝试在另一个线程上访问SWT对象,就会出现此错误。考虑使用Display.syncExec()
或Display.asyncExec()
将与SWT相关的处理移动到主线程中。使用syncExec()
时要注意不要引起死锁。
Runnable uiUpdater = new Runnable() {
public void run() {
// update SWT UI safely here
// ...
}
};
Job longRunningOperation = new Job("My command") {
protected IStatus run(IProgressMonitor monitor) {
// some time consuming code here
// ...
Display.getDefault().asyncExec(uiUpdater);
return Status.OK_STATUS;
}
};
longRunningOperation.schedule();
Display.syncExec()
或 Display.asyncExec()
可以解决你的问题。根据您需要在后台执行的任务,您可能需要查看Eclipse Jobs API,该API提供了运行后台任务并向用户提供反馈的支持。搜索“eclipse jobs tutorial”,这里有一个很好的教程:http://www.vogella.com/articles/EclipseJobs/article.html
当你的代码在点击按钮或类似操作时,这种情况永远不会发生,但是当你使用后台进程或异步通知时,它会一直发生。
有一个解决方案:在特定的块中执行你的代码:
Display.getDefautl().syncExec(new Runnable() {
public void run() {
// code related to GUI element(s)
}
}
或者
Display.getDefautl().asyncExec(new Runnable() {
public void run() {
// code related to GUI element(s)
}
}
你应该使用 Display.getDefault().asyncExec() 或 Display.getDefault().syncExec()。
示例代码:
@PostConstruct
public void createControls(Composite parent) {
.... \\ label definition
}
public void updateInterface(String message)
{
try{
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
try{
label.setText(message);
}
catch(Exception exc){
System.out.println(exc);
}
}
});
}
catch(Exception exception){
System.out.println(exception);
}
}