ProgressMonitorDialog和InvocationTargetException中的“取消"按钮 [英] Cancel button in ProgressMonitorDialog and InvocationTargetException
问题描述
在我的应用程序中,我生成一个报告.操作时间从几秒钟到几小时不等.为了通知用户,我使用ProgressMonitorDialog
.
始终在大约70分钟后抛出InvocationTargetException
.我不知道为什么会这样.
In my application, I generate a report. Time of the operation is from a few seconds to up to several hours. To inform the user I use ProgressMonitorDialog
.
Always after about 70 minutes InvocationTargetException
is thrown. I have no idea why this is happening.
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.我尝试了以下解决方案,但由于变量退出将是最终的,因此无法正常工作.
The second problem is the cancellation of the window with the progress of work. I know that pressing the "cancel" button, the method isCanceled()
returns true. I tried the following solution, but it can not work because the variable exit would be final.
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();
}
推荐答案
您遇到了最常见的SWT异常,即无效的线程访问".
You came across the most common SWT exception which is "Invalid thread access".
这基本上意味着您正在尝试从不是UI线程的线程更新UI.除非您使用特定的技术来做到这一点,否则在SWT中是不允许的.
It basically means that you are trying to update the UI from a thread that is not the UI-thread. This isn't allowed in SWT, unless you use a specific technique to do it.
您可以在官方Wiki中中了解更多信息.
You can read more about it in the official wiki.
您发布的代码似乎还可以,您可能在controller.generate(model);
中的其他地方存在问题.如果看不到相关代码,我无法为您提供进一步的帮助.
The code you posted seems to be ok, you're problem is probably somewhere else in controller.generate(model);
. I can't help you further without seeing the relevant code.
同时,这是您应如何从非UI线程与UI交互的方法:
In the meantime, this is how you should interact with the UI from a non-UI-thread:
Display.getDefault().asyncExec(new Runnable() {
public void run() {
... do any work that updates the screen ...
}
});
更新
好的,这是一个更新,应该向您展示如何将ProgressMonitorDialog
与Display#asyncExec()
结合使用:
Ok, here is an update that should show you how the ProgressMonitorDialog
should be used in combination with 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();
}
});
}
请注意,只有实际的UI交互包装在Display.asyncExec()
中.这样,您仍然可以在每次迭代中检查monitor.isCanceled()
.
Note that only the actual UI interaction is wrapped in Display.asyncExec()
. This way, you can still check monitor.isCanceled()
in each iteration.
这篇关于ProgressMonitorDialog和InvocationTargetException中的“取消"按钮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!