在我的应用程序中,我生成一个报告。操作时间从几秒到几个小时。要通知用户我使用ProgressMonitorDialog
。
总是在大约70分钟之后抛出InvocationTargetException
。我不知道为什么会这样。
try {
new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
monitor.beginTask("Something...", IProgressMonitor.UNKNOWN);
controller.generate(model);
monitor.done();
}
});
} catch (InvocationTargetException | InterruptedException e) {
logger.error(e);
}
堆栈追踪:
java.lang.reflect.InvocationTargetException
at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:421)
at org.eclipse.jface.dialogs.ProgressMonitorDialog.run(ProgressMonitorDialog.java:507)
at pl.edu.prz.allegroapi.gui.report.ProductReport$4.widgetSelected(ProductReport.java:323)
at org.eclipse.swt.widgets.TypedListener.handleEvent(Unknown Source)
at org.eclipse.swt.widgets.EventTable.sendEvent(Unknown Source)
at org.eclipse.swt.widgets.Widget.sendEvent(Unknown Source)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Unknown Source)
at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
at pl.edu.prz.allegroapi.gui.report.ProductReport.open(ProductReport.java:91)
at pl.edu.prz.allegroapi.gui.MainWindow$2.widgetSelected(MainWindow.java:126)
at org.eclipse.swt.widgets.TypedListener.handleEvent(Unknown Source)
at org.eclipse.swt.widgets.EventTable.sendEvent(Unknown Source)
at org.eclipse.swt.widgets.Widget.sendEvent(Unknown Source)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Unknown Source)
at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
at pl.edu.prz.allegroapi.gui.MainWindow.open(MainWindow.java:75)
at pl.edu.prz.allegroapi.tasks.CreateGuiTask.doStartup(CreateGuiTask.java:46)
at pl.edu.prz.allegroapi.tasks.CreateGuiTask.access$0(CreateGuiTask.java:42)
at pl.edu.prz.allegroapi.tasks.CreateGuiTask$1.run(CreateGuiTask.java:31)
at java.lang.Thread.run(Unknown Source)
Caused by: org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.widgets.Widget.error(Unknown Source)
at org.eclipse.swt.widgets.Widget.checkWidget(Unknown Source)
at org.eclipse.swt.widgets.Dialog.checkParent(Unknown Source)
at org.eclipse.swt.widgets.Dialog.<init>(Unknown Source)
at org.eclipse.swt.widgets.MessageBox.<init>(Unknown Source)
at pl.edu.prz.allegroapi.gui.report.ProductReportController.generate(ProductReportController.java:59)
at pl.edu.prz.allegroapi.gui.report.ProductReport$4$1.run(ProductReport.java:335)
at org.eclipse.jface.operation.ModalContext$ModalContextThread.run(ModalContext.java:121)
第二个问题是随着工作进度取消窗口。我知道按“取消”按钮,方法isCanceled()
返回true。我尝试了以下解决方案,但它无法工作,因为变量exit将是最终的。
Boolean exit = false;
display.asyncExec(new Runnable() {
public void run() {
controller.generate(model);
exit=true;
}
});
try {
new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
monitor.beginTask("Something...", IProgressMonitor.UNKNOWN);
while(!monitor.isCanceled() && !exit) {
Thread.sleep(1000);
}
} finally {
monitor.done();
}
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
答案 0 :(得分:3)
您遇到了最常见的SWT异常,即&#34;无效的线程访问&#34;。
它基本上意味着您尝试从不是UI线程的线程更新UI。除非您使用特定技术进行此操作,否则SWT中不允许这样做。
您可以详细了解in the official wiki。
您发布的代码似乎没问题,您的问题可能是controller.generate(model);
中的其他地方。如果没有相关代码,我无法帮助您。
与此同时,这就是你应该如何从非UI线程与UI进行交互:
Display.getDefault().asyncExec(new Runnable() {
public void run() {
... do any work that updates the screen ...
}
});
<强>更新强>
好的,这是一个更新,应该向您展示ProgressMonitorDialog
应该如何与Display#asyncExec()
结合使用:
public static void main(String[] args)
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new GridLayout(1, false));
final Label label = new Label(shell, SWT.NONE);
Button button = new Button(shell, SWT.PUSH);
button.setText("Start");
button.addListener(SWT.Selection, new Listener()
{
@Override
public void handleEvent(Event arg0)
{
try
{
new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress()
{
@Override
public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException
{
try
{
monitor.beginTask("Something...", IProgressMonitor.UNKNOWN);
for (int i = 0; i < 100; i++)
{
/* Check if the monitor has been canceled */
if (monitor.isCanceled())
return;
try
{/* Only wrap the UI interaction in the asyncExec */
doFancyUIStuff(label, i);
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
finally
{
monitor.done();
}
}
});
}
catch (InvocationTargetException e)
{
e.printStackTrace();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
});
shell.pack();
shell.open();
while (!shell.isDisposed())
{
while (!display.readAndDispatch())
{
display.sleep();
}
}
}
private static void doFancyUIStuff(final Label label, final int index)
{
Display.getDefault().asyncExec(new Runnable()
{
@Override
public void run()
{
label.setText(index + "");
label.getParent().layout();
}
});
}
请注意,只有实际的用户界面互动才会包含在Display.asyncExec()
中。这样,您仍然可以在每次迭代中检查monitor.isCanceled()
。