How can I correctly update a progress bar for an operation of unknown duration within an Eclipse wizard?

非 Y 不嫁゛ 提交于 2020-01-03 16:57:55

问题


I have implemented a wizard for my Eclipse plug-in, showing several pages. One of these pages needs some lengthy initialization, that means it consists of a SWT table, which needs to be populated by information coming from an external source. This source needs to be activated first (one single method call that returns after a couple of seconds - I can not know in advance how long it will take exactly), before it can be used as input for for the table viewer. This initialization is currently done by the table model provider when it needs to access the external source for the first time.

Therefore, when I enter the wizard page, I would like to show a dummy progress bar that just counts up for a while. My approach was the following, but unfortunately does not work at all:

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);
    }
}

This method gets then invoked when the wizard page's setVisible()-method is called and should, after a couple of seconds, set the viewer's input. This, however, never happens, because the inner-most run()-method never gets executed.

Any hints on how to deal with long-running (where an exact estimate is not available) initializations in Eclipse wizards would be very appreciated!


回答1:


I assume the reason why it's "not working" for you is that the preparation of input is done in UI thread meaning that the progress bar cannot be updated. A better approach is to prepare input in advance and only set input to viewer after that.




回答2:


I have given below a simple example on how to use IRunnableWithProgress along with a ProgressMonitorDialog to perform a task of unknown quantity. To start with, have an implementation to IRunnableWithProgress from where the actual task is performed. This implementation could be an inner class.

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();
    }
}

Now, a generic implementation to ProgressMonitorDialog can be created as below which could be used for other places where a progress monitor dialog is required.

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;
    }
}

Having got the required implementation, the task can be invoked as below to get it processed with a progress dialog.

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();
}

Hope this helps!



来源:https://stackoverflow.com/questions/7636020/how-can-i-correctly-update-a-progress-bar-for-an-operation-of-unknown-duration-w

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!