ProgressWorker is a SwingWorker extension, providing a fluent API for constructing background task workers for a variety of task types.
All handlers get called on the EventDispatchThread.
Note
|
Like SwingWorker, ProgressWorker instances can not be reused. Tasks, on the other hand, can be made stateful and reusable if required. |
1. Task
// A non-progress aware task, producing no result
ProgressWorker.Task task = () -> {
// Perform the task
};
ProgressWorker.builder(task)
.onException(exception ->
exceptionDialog()
.owner(applicationFrame)
.show(exception))
.execute();
2. ResultTask
// A non-progress aware task, producing a result
ProgressWorker.ResultTask<String> task = () -> {
// Perform the task
return "Result";
};
ProgressWorker.builder(task)
.onResult(result ->
showMessageDialog(applicationFrame, result))
.onException(exception ->
exceptionDialog()
.owner(applicationFrame)
.show(exception))
.execute();
3. ProgressTask
// A progress aware task, producing no result
ProgressWorker.ProgressTask<String> task = progressReporter -> {
// Perform the task
progressReporter.report(42);
progressReporter.publish("Message");
};
ProgressWorker.builder(task)
.onProgress(progress ->
System.out.println("Progress: " + progress))
.onPublish(message ->
showMessageDialog(applicationFrame, message))
.onException(exception ->
exceptionDialog()
.owner(applicationFrame)
.show(exception))
.execute();
4. ProgressResultTask
// A reusable, cancellable task, producing a result.
// Displays a progress bar in a dialog while running.
var task = new DemoProgressResultTask();
ProgressWorker.builder(task.prepare(142))
.onStarted(task::started)
.onProgress(task::progress)
.onPublish(task::publish)
.onDone(task::done)
.onCancelled(task::cancelled)
.onException(task::failed)
.onResult(task::finished)
.execute();
static final class DemoProgressResultTask implements ProgressResultTask<Integer, String> {
private final JProgressBar progressBar = progressBar()
.indeterminate(false)
.stringPainted(true)
.string("")
.build();
// Indicates whether the task has been cancelled
private final AtomicBoolean cancelled = new AtomicBoolean();
// A Control for setting the cancelled state
private final Control cancel = Control.builder()
.command(() -> cancelled.set(true))
.caption("Cancel")
.mnemonic('C')
.build();
// A panel containing the progress bar and cancel button
private final JPanel progressPanel = borderLayoutPanel()
.centerComponent(progressBar)
.eastComponent(button(cancel).build())
.build();
// The dialog displaying the progress panel
private final JDialog dialog = componentDialog(progressPanel)
.owner(applicationFrame)
// Trigger the cancel control with the Escape key
.keyEvent(KeyEvents.builder(VK_ESCAPE)
.action(cancel))
// Prevent the dialog from closing on Escape
.disposeOnEscape(false)
.build();
private int taskSize;
@Override
public int maximumProgress() {
return taskSize;
}
@Override
public Integer execute(ProgressReporter<String> progressReporter) throws Exception {
List<Integer> result = new ArrayList<>();
for (int i = 0; i < taskSize; i++) {
Thread.sleep(50);
if (cancelled.get()) {
throw new CancelException();
}
result.add(i);
reportProgress(progressReporter, i);
}
return result.stream()
.mapToInt(Integer::intValue)
.sum();
}
// Makes this task reusable by resetting the internal state
private DemoProgressResultTask prepare(int taskSize) {
this.taskSize = taskSize;
progressBar.getModel().setMaximum(taskSize);
cancelled.set(false);
return this;
}
private void reportProgress(ProgressReporter<String> reporter, int progress) {
reporter.report(progress);
if (progress < taskSize * 0.5) {
reporter.publish("Going strong");
}
else if (progress > taskSize * 0.5 && progress < taskSize * 0.85) {
reporter.publish("Half way there");
}
else if (progress > taskSize * 0.85) {
reporter.publish("Almost done");
}
}
private void started() {
dialog.setVisible(true);
}
private void progress(int progress) {
progressBar.setValue(progress);
}
private void publish(List<String> strings) {
progressBar.setString(strings.get(0));
}
private void done() {
dialog.setVisible(false);
}
private void cancelled() {
showMessageDialog(applicationFrame, "Cancelled");
}
private void failed(Exception exception) {
exceptionDialog()
.owner(applicationFrame)
.show(exception);
}
private void finished(Integer result) {
showMessageDialog(applicationFrame, "Result : " + result);
}
}