Eclipse Search

Loading

Feb 12, 2009

Using progress bars ...

In the last tip, I said the top most mistake done by Eclipse plug-in developers is running long running operations in the UI thread. Assuming that you are running it in a non-UI thread, how to show the progress of the execution? Obviously thru progress monitors. But how many different ways are there to show a progress monitor? Lets see them in this tip.
The first option is ProgressMonitorDialog. You have to create a IRunnableWithProgress and use the run method:
ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
dialog.run(true, true, new IRunnableWithProgress(){
    public void run(IProgressMonitor monitor) {
        monitor.beginTask("Some nice progress message here ...", 100);
        // execute the task ...
        monitor.done();
    }
});
Result:
 ProgressMonitorDialog
As you can see, the dialog is kind-of blocking the user. This dialog is advisable only in the rare cases where the user have to wait till the operation is completed. In most other cases, you should prefer running a Job. A Job is not blocking to the user and can still show the progress. The progress is available in the Progress View.

Job job = new Job("My new job") {
    @Override
    protected IStatus run(IProgressMonitor monitor) {
        monitor.beginTask("Some nice progress message here ...", 100);
        // execute the task ...
        monitor.done();
        return Status.OK_STATUS;
    }
};
job.schedule();

Result:
 Job in Progress View

If you make the job as a user job by calling setUser(true), the progress dialog will be opened, where the user can chose to run the job as a background job. If the user doesn't want to see this dialog again, he can select to 'Always run in background':



When the job is initiated by the user interacting with a workbench part (like clicking a button in a view), a better way to schedule the job is thru the site's IWorkbencSiteProgressService.schedule. When the job begins to execute, the workbench part can show it visually. The default behaviour is to italize the part name:
WorkbenchPart.showBusy
But you can customize it by overriding the showBusy() method in your WorkbenchPart:
public void showBusy(boolean busy) {
    super.showBusy(busy);
    if(busy)
        setPartName("I'm doing a job right now...");
    else
        setPartName("Sample View");
}
Result:
WorkbenchPart.showBusy

In case your action doesn't have any WorkbenchPart associated with it, you can use the IWorkbenchWindow.run(...) to show the progress:

IWorkbenchWindow.run

If you are running a long running operation in a wizard/wizardPage you should consider running it thru getContainer().run(). This will show the progressBar right there in the wizard dialog itself:

progressbar in wizard

If you are updating the UI elements in the wizardPage during the execution, you have to note that if you do a setEnabled() on any widget, it won't reflect. Its because the container registers the enabled state of the widgets before execution; disables the widgets; executes the task and restores the widget's enabled state to the saved value. So if you have changed the state during the operation, it will be overwritten by the container.

In case, you can't display a progressbar, you should at least use BusyIndicator.showWhile() and display the busy cursor to show that some operation is being executed. Else the user might be wondering why the UI is frozen.

33 comments:

  1. This is probably the most concise explanation of where and how to use progress services in eclipse I've seen.

    I find there is a lot of separate doco on individual services and "things" in eclipse, but nothing that ties them all together to describing their usage patterns. (When to use X over Y).

    Well done.
    ReplyDelete
  2. Awesome! It's nice to see such a concise post of how to implement a piece functionality and the different scenarios that apply. One of the best eclipse tips ever!
    ReplyDelete
  3. Hi Prakash,
    the Tip seems to be cool and simple. The status line is not colored(green/blue) on my dialog. I don't know why. May you have an idea?! Please let me know. I definitely will use this code in my application.
    Thanks,
    Simpson
    ReplyDelete
  4. @Freaky-namuH and @sud,
    Thanks. Will continue to write these kind of tips.

    @Simpson,
    Did you make any changes in the colors or themes in the Preferences?
    ReplyDelete
  5. Hello,
    you wrote that it is possible to run the job via IWorkbenchWindow.run(). I like the look of this progress bar because the user can cancel the job without having a big window on top.

    But I saw that the run-method takes only a IRunnableWithProgress and we are completely using the eclipse job framework.

    Is there a way to show the job in the way you mentioned in the article?

    Thanks,
    Jens
    ReplyDelete
  6. @Jens,
    Only IRunnableWithProgress can be run in a IRunnableContext - not Job. I don't think there is a direct way to do it. Making your job to implement IRunnableWithProgress also won't work, as the run method in both the places differ only by the return value - which is not allowed in Java.

    In short, there might be a hack, but I don't know :-(
    ReplyDelete
  7. Hi Prakash,
    thanks for answering my question about the color of the status line. All the preference settings are default. May be need enable/disable something!?!
    Simpson
    ReplyDelete
  8. Great tip. Thanks a lot.
    ReplyDelete
  9. I made use of your tip today in my work . Thanks prakash
    ReplyDelete
  10. I am amazed! this is the most comprehensive yet concise, useful and to the point explanation of anything. thank you. this has saved me a lot of time and probably would have saved me the last 2 days if I had found this earlier. :)
    ReplyDelete
  11. Hi,
    Is there a way to show animated gif as TitleImage while view is working?
    ReplyDelete
  12. @Kubu,
    I don't think animated gif will work in the view's title image. You may have to cycle thru individual icons. Check Mylyn code, their editor seems to have that functionality
    ReplyDelete
  13. Thanks Prakash,

    If I run the following lines of code in an editor:

    this.miningJob = new MiningJob();
    this.miningJob.setPriority(Job.LONG);
    this.miningJob.setUser(true);
    IWorkbenchSiteProgressService progressService = (IWorkbenchSiteProgressService)getSite().getService(IWorkbenchSiteProgressService.class);
    progressService.schedule(this.miningJob);

    the MiningJob will be scheduled and run, but nothing will appear in the status line. Do you know why ? Am I missing something ?

    Damien
    ReplyDelete
  14. I found the problem. I had to add the following line to the contents of the method preWindowOpen() of my ApplicationWorkbenchWindowAdvisor:

    configurer.setShowProgressIndicator(true);

    Now I have another problem: nothing will happen when I click on the progress icon of the status line while the job is running. I was expecting the ProgressView to be brought to front, but I have to do that myself by clicking on the ProgressView tab :(.

    Have you ever heard of that problem ?

    Many thanks in advance,
    Damien
    ReplyDelete
  15. Hi Prakash

    ProgressMonitorDialog dialog = new ProgressMonitorDialog(Display.getDefault().getActiveShell());
    try {
    dialog.run(true, true, new IRunnableWithProgress(){
    public void run(IProgressMonitor monitor) {
    monitor.beginTask("Deployment in progress", 100);
    // I want call a method (say Deployment) which takes lot of time( I dont know exactly how much)
    // But it doesnt show me progress. Only i do call monitor.worked(work) it shows .
    // but But that is not correct progress .. how to go abt ..

    monitor.setTaskName("Deployment Completed.");
    monitor.done();
    }
    });
    } catch (InvocationTargetException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    I dont how to go about
    I have added the comments , problems

    Regards
    Govind
    ReplyDelete
  16. @Govind,
    Try this:
    monitor.beginTask("Deployment in progress", IProgressMonitor.Unknown);
    ReplyDelete
  17. Thanks a lot prakash... :)

    One more thing is it possible remove the cancel button . ??

    Thanks and Regards
    Govind R Ashrit
    ReplyDelete
  18. @goivnd,
    See: http://blog.eclipse-tips.com/2009/01/top-10-mistakes-in-eclipse-plug-in.html

    What does run(true, true, ...) means ;-)
    ReplyDelete
  19. Hi Prakash..
    i over looked that ..
    Thanks a lot..
    ReplyDelete
  20. Hi Prakash

    dialog.run(true, false, new IRunnableWithProgress(){
    public void run(IProgressMonitor monitor) {
    onitor.beginTask("Sync", 100);
    monitor.beginTask(".Please wait...", IProgressMonitor.UNKNOWN);
    table.getItems();
    monitor.done();
    }
    });

    When i do this i get
    Caused by: org.eclipse.swt.SWTException: Invalid thread access

    How can we acess other swt controls
    Regards
    Govind R
    ReplyDelete
  21. @Govind
    It would be impossible for me to answer all the queries. You can check http://eclipse.org/forums for more help
    ReplyDelete
  22. I'm monitoring the progress of a job using the following:

    Job job = new Job("My new job") {
    protected IStatus run(IProgressMonitor monitor) {
    ...
    }
    job.schedule();

    Is it possible to be notified the moment the user presses the Cancel Button, rather than waiting until a monitor sub task is completed and responding to:

    monitor.isCanceled()

    Cheers
    ReplyDelete
  23. @Anon,

    Canceling is not notified with any events. Its up to the job to check the flat and perform the cancel.
    ReplyDelete
  24. Hi Prakash,

    The post is amazing.. I have a doubt. I'm stuck with it..The task which i am executing may take different time for finishing up each time. I tried your previous suggestion of using IProgressMonitor.Unknown.. It works good.. But in my case I want the progress to be displayed as continuous progress(as in normal cases) in the bar and not as the one moving from end to end. Any suggestions.. ?
    ReplyDelete
  25. Hey Dude!

    Thanks! It's about time someone put out something on progress indicators. All those eclipse programmers with too much to do - no one's been able to explain it as simple as this.
    Keep up the good work!
    ReplyDelete
  26. Hi Prakash,

    Awesome post. Helped me very much :D

    Thanks a lot..
    ReplyDelete
  27. Hi Prakash,

    thanks for all of these hints. But what about using IProgressService which can be obtained by

    PlatformUI.getWorkbench().getProgressService()

    Is there some specific reason why you did not mention that in your tip?
    I have found the

    busyCursorWhile (IRunnableWithProgress runnable)

    method to be very handy at times.

    Thanks again for your explanations!
    ReplyDelete
  28. Hi Prakash,

    this was very helpful

    Thanks a lot..
    ReplyDelete
  29. I want to add a progress bar to my dialog, and control its progress through a Job. Can I do it? If yes, how?

    Thanks,
    Rehman
    ReplyDelete
  30. try IWorkbenchWindow.run(...). but no progress bar showing
    ReplyDelete
  31. I was stuck on this for a while - to get the Progres Bar to show in a Wizard you need to add:

    @Override
    public boolean needsProgressMonitor()
    {
    return true;
    }

    To your Wizard.
    ReplyDelete
  32. Is it possible to be notified the moment the user presses the Cancel Button, rather than waiting until a monitor sub task is completed and responding to:

    monitor.isCanceled()
    ReplyDelete