ProgressMonitorDialog和InvocationTargetException中的“取消"按钮 [英] Cancel button in ProgressMonitorDialog and InvocationTargetException

查看:144
本文介绍了ProgressMonitorDialog和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 ...
    }
});


更新

好的,这是一个更新,应该向您展示如何将ProgressMonitorDialogDisplay#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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆