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.

21 comments:

Freaky-namuH said...

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.

sud said...

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!

Anonymous said...

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

Prakash G.R. said...

@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?

Anonymous said...

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

Prakash G.R. said...

@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 :-(

Anonymous said...

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

Jan said...

Great tip. Thanks a lot.

anumeval said...

I made use of your tip today in my work . Thanks prakash

plasticfloor said...

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. :)

Kubu said...

Hi,
Is there a way to show animated gif as TitleImage while view is working?

Prakash G.R. said...

@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

Anonymous said...

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

Anonymous said...

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

goivnd said...

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

Prakash G.R. said...

@Govind,
Try this:
monitor.beginTask("Deployment in progress", IProgressMonitor.Unknown);

goivnd said...

Thanks a lot prakash... :)

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

Thanks and Regards
Govind R Ashrit

Prakash G.R. said...

@goivnd,
See: http://blog.eclipse-tips.com/2009/01/top-10-mistakes-in-eclipse-plug-in.html

What does run(true, true, ...) means ;-)

goivnd said...

Hi Prakash..
i over looked that ..
Thanks a lot..

goivnd said...

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

Prakash G.R. said...

@Govind
It would be impossible for me to answer all the queries. You can check http://eclipse.org/forums for more help

Post a Comment

Followers

Disclaimer

Any opinion expressed here, in any other blogs, forums, websites, "Letters to the Editor" column in "The Hindu" daily, weekly magazine’s sudoku column, my daughter’s drawing book and scribbling on the toilet papers, are not necessary my employers opinion, but all my own :-P

Unless specified, all the content of this blog is made available under Eclipse Public License
 
Design by Wpthemedesigner. Converted To Blogger Template By Anshul .