如何在Eclipse向导中正确更新未知持续时间操作的进度条?

时间:2011-10-03 13:57:51

标签: eclipse swt progress

我为Eclipse插件实现了一个向导,显示了几个页面。其中一个页面需要一些冗长的初始化,这意味着它由一个SWT表组成,需要由来自外部源的信息填充。需要首先激活此源(一个单一的方法调用,在几秒钟之后返回 - 我无法预先知道它将需要多长时间),然后才能将其用作表查看器的输入。当初始化需要首次访问外部源时,表初始化由表模型提供程序完成。

因此,当我进入向导页面时,我想显示一个虚拟进度条,它只会计算一段时间。我的方法如下,但遗憾的是根本不起作用:

private void initViewer() {
    IRunnableWithProgress runnable = new IRunnableWithProgress() { // needed to embed long running operation into the wizard page

        @Override
        public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
            SubMonitor progress = SubMonitor.convert(monitor);

            Thread thread = new Thread() {
                @Override
                public void run() {
                    Display.getDefault().syncExec(new Runnable() {
                        public void run() {
                            viewer.setInput(ResourcesPlugin.getWorkspace().getRoot()); // this will make the table provider initialize the external source.
                        }
                    });
                }
            };

            thread.start();

            while(thread.isAlive()) {
                progress.setWorkRemaining(10000);
                progress.worked(1);
            }

            progress.done();
        }

    };

    try {
        getContainer().run(false, false, runnable);
    } catch(Exception e) {
        throw new Exception("Could not access data store", e);
    }
}

当调用向导页面的setVisible() - 方法时,会调用此方法,并在几秒钟后设置查看器的输入。但是,这绝不会发生,因为最内部的run() - 方法永远不会被执行。

有关如何处理长期运行(无法获得准确估计值)的任何提示,我们将非常感谢Eclipse向导中的初始化!

2 个答案:

答案 0 :(得分:1)

我认为它“无法正常工作”的原因是输入的准备是在UI线程中完成的,这意味着无法更新进度条。更好的方法是提前准备输入,然后在此之后仅向观众设置输入。

答案 1 :(得分:1)

我在下面给出了一个简单的示例,说明如何使用IRunnableWithProgressProgressMonitorDialog执行未知数量的任务。首先,从执行实际任务的地方获得IRunnableWithProgress的实现。这个实现可能是一个内部类。

public class MyRunnableWithProgress implements IRunnableWithProgress {
    private String _fileName;

    public MyRunnableWithProgress(String fileName) {
        _fileName = fileName;
    }

    @Override
    public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
        int totalUnitsOfWork = IProgressMonitor.UNKNOWN;
        monitor.beginTask("Performing read. Please wait...", totalUnitsOfWork);
        performRead(_fileName, monitor); // This only performs the tasks
        monitor.done();
    }
}

现在,可以创建 ProgressMonitorDialog 的通用实现,如下所示,可以用于需要进度监视器对话框的其他地方。

public class MyProgressMonitorDialog extends ProgressMonitorDialog {

    private boolean cancellable;

    public MyProgressMonitorDialog(Shell parent, boolean cancellable) {
        super(parent);
        this.cancellable = cancellable;
    }

    @Override
    public Composite createDialogArea(Composite parent) {
        Composite container = (Composite) super.createDialogArea(parent);
        setCancelable(cancellable);
        return container;
    }
}

获得所需的实现后,可以按如下方式调用该任务,以使用进度对话框处理该任务。

boolean cancellable = false;
IRunnableWithProgress myRunnable  = new MyRunnableWithProgress(receivedFileName);
ProgressMonitorDialog progressMonitorDialog = new MyProgressMonitorDialog(getShell(), cancellable);

try {
    progressMonitorDialog.run(true, true, myRunnable);
} catch (InvocationTargetException e) {
    // Catch in your best way
    throw new RuntimeException(e);
} catch (InterruptedException e) {
    //Catch in your best way
    Thread.currentThread().interrupt();
}

希望这有帮助!