How to report progress from long-running tasks
Using progress monitor arguments
The class com.bc.ceres.ProgressMonitor is generally used to report progress in log running tasks. Many framework callbacks provide an instance of this interface to client functions.
void archiveInternet(ProgressMonitor pm) {
try {
pm.beginTask("Archiving internet", 100);
// Here: perform 20% of the work (download)
pm.worked(20);
// Here: perform 50% of the work (zip)
pm.worked(50);
// Here: perform remaining 30% work (copy)
pm.worked(30);
} finally {
pm.done();
}
}Or pass sub-progess monitors to sub-functions:
void archiveInternet(ProgressMonitor pm) {
try {
pm.beginTask("Archiving internet", 100);
// Here: perform 20% of the work (download)
downloadInternet(SubProgressMonitor.create(pm, 20));
// Here: perform 50% of the work (zip)
zipDownloadedInternet(SubProgressMonitor.create(pm, 50));
// Here: perform remaining 30% work (copy)
copyInternetZip(SubProgressMonitor.create(pm, 30));
} finally {
pm.done();
}
}Not shown in the code above is the check for cancelation. A user may have requested to cancel a long-running task. This is reported through the ProgressMonitor.isCanaceled() method.
void archiveInternet(ProgressMonitor pm) {
...
for (...) {
...
if (pm.isCancelled()) {
return; // or throw new CanceledException();
}
...
}
...
}Calling of methods that take a progress monitor argument
If you can't or don't want to report progress you can simply pass a null progress monitor (but don't pass null):
archiveInternet(ProgressMonitor.NULL);From command-line tools, you can use:
archiveInternet(new PrintWriterProgressMonitor(System.out));From GUI code, we ustilise the adapter class org.esa.snap.rcp.util.ProgressHandleMonitor to report progress through ProgressMonitor interface but using NetBeans progress bars. As long running tasks should not be called from the Swing event dispatcher thread (EDT), we will have to create or reuse background threads to do so. The NetBeans org.netbeans.api.progress.ProgressUtils API provides some useful methods for this:
ProgressHandleMonitor pm = ProgressHandleMonitor.create("Archiving internet");
Runnable operation = () -> {
archiveInternet(pm);
};
ProgressUtils.runOffEventThreadWithProgressDialog(operation, "Archiving internet",
pm.getProgressHandle(),
true,
50, // time in ms after which wait cursor is shown
1000); // time in ms after which dialog with "Cancel" button is shownOr using the NetBeans class org.openide.util.RequestProcessor:
RequestProcessor.getDefault().post(() -> {
ProgressHandle handle = ProgressHandleFactory.createHandle("Archiving internet");
ProgressMonitor pm = new ProgressHandleMonitor(handle);
archiveInternet(pm);
});Documentation of NetBeans Progress API:
http://bits.netbeans.org/8.0/javadoc/org-netbeans-api-progress/
http://bits.netbeans.org/8.0/javadoc/org-openide-util/org/openide/util/RequestProcessor.html
also see book NetBeans for Beginners (nb4beginners.pdf)
In older code you will find uses of the com.bc.ceres.swing.progress.ProgressMonitorSwingWorker class. Don't use it as it will cause the main frame to go into background and let other desktop windows hide it. Very annoying for users (and us developers).