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
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 shown
Or 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://wiki.netbeans.org/BookNBPlatformCookbookCH0210
- 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).