Never before I had to take care about this, so I knew only that, there were some progress monitors, which I had to pass to some methods. I started digging into the web and found two very good articles: How to Correctly and Uniformly Use Progress Monitors and FAQ How do I use progress monitors? . Both documents contain very useful information and give nice examples. However, these two papers describe the approach in which class SubProgressMonitor is used. This solution is good, but why use good solution, when better one can be used? Since Eclipse 3.3 class SubMonitor is available (in the project org.eclipse.equinox.common in package org.eclipse.core.runtime) and this is a very good news. Why?
Basically because:
- we don't have to call methods beginTask() and done() on the instance of SubMonitor class
- it is easier now to create submonitors (there is a method newChild(int totalWork))
- in SubMonitor we can find method setWorkRemining() which allows us to redistribute the remaining space on the progress monitor
- SubMonitor protects the caller from common progress reporting bugs in a called method
First of all we have to convert any other kind of progress monitor into SubMonitor. This is very easy, because we can use one of two static methods:
public static SubMonitor convert(IProgressMonitor monitor, int work)
and
public static SubMonitor convert(IProgressMonitor monitor, String taskName, int work)
So after invoking:
SubMonitor progress = SubMonitor.convert(monitor, 100);
we can benefit from all the advances of SubMonitor class.
The basic example of using SubMonitor could look like this:
My main concern about reporting the progress was how to manipulate the number of work items, when some operation will or will not be executed (so when we have a condition). Fortunately with SubMonitor it is pretty easy. The example below shows how to do this:void someOperation(IProgressMonitor monitor) {
// Convertion of the given monitor
SubMonitor progressSubMonitor = SubMonitor.convert(monitor, 100);// 70% of work is consumed
doSomeWork(progressSubMonitor.newChild(70));// 30% of work is consumed
progressSubMonitor.worked(30);}
void someOperation(IProgressMonitor monitor) {
SubMonitor progressSubMonitor = SubMonitor.convert(monitor, 100);
if (condition) {
// 50% of work is consumed
doSomeWork(progressSubMonitor.newChild(40));
}//if there is any work item resumed from the first 40% then use it
progress.setWorkRemaining(40);// the rest of work items is consumed
doSomeWork(progress.newChild(60));
}
It is also easy to handle the loop case:
void someOperation(IProgressMonitor monitor, Collection someCollection) {SubMonitor progressSubMonitor = SubMonitor.convert(monitor, 100);
// Create a new progress monitor that uses 70% of the total progress
SubMonitor loopProgress = progressSubMonitor.newChild(70);// Allocate one tick for each element of the given collection.
loopProgress.setWorkRemaining(someCollection.size());for (Iterator iter = someCollection.iterator(); iter.hasNext();) {
Object next = iter.next();
//Do something with the element from collection and
//consume one work item
doSomeWorkOnElement(next, loopProgress.newChild(1));
}// Use the remaining 30% of the progress monitor to do some work outside
}
// the loop
doSomeWork(progressSubMonitor .newChild(30));
Have fun with using SubMonitor ;-)
No comments:
Post a Comment