import java.util.concurrent.atomic.AtomicBoolean; import javafx.application.Application; import javafx.beans.binding.Bindings; import javafx.beans.binding.StringBinding; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.concurrent.Task; import javafx.concurrent.Worker; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.SceneBuilder; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ProgressBar; import javafx.scene.control.ProgressBarBuilder; import javafx.scene.layout.BorderPaneBuilder; import javafx.scene.layout.ColumnConstraintsBuilder; import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPaneBuilder; import javafx.scene.layout.HBox; import javafx.scene.layout.HBoxBuilder; import javafx.stage.Stage; public class WorkerAndTaskExample extends Application { private Model model; private View view; public static void main(String[] args) { Application.launch(args); } public WorkerAndTaskExample() { model = new Model(); } @Override public void start(Stage stage) throws Exception { view = new View(model); hookupEvents(); stage.setTitle("Worker and Task Example"); stage.setScene(view.scene); stage.show(); } private void hookupEvents() { view.startButton.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent actionEvent) { new Thread((Runnable) model.worker).start(); } }); view.cancelButton.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent actionEvent) { model.worker.cancel(); } }); view.exceptionButton.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent actionEvent) { model.shouldThrow.getAndSet(true); } }); } private static class Model { public Worker<String> worker; public AtomicBoolean shouldThrow = new AtomicBoolean(false); private Model() { worker = new Task<String>() { @Override protected String call() throws Exception { updateTitle("Example Task"); updateMessage("Starting..."); final int total = 250; updateProgress(0, total); for (int i = 1; i <= total; i++) { try { Thread.sleep(20); } catch (InterruptedException e) { return "Cancelled at " + System.currentTimeMillis(); } if (shouldThrow.get()) { throw new RuntimeException("Exception thrown at " + System.currentTimeMillis()); } updateTitle("Example Task (" + i + ")"); updateMessage("Processed " + i + " of " + total + " items."); updateProgress(i, total); } return "Completed at " + System.currentTimeMillis(); } }; } } private static class View { public ProgressBar progressBar; public Label title; public Label message; public Label running; public Label state; public Label totalWork; public Label workDone; public Label progress; public Label value; public Label exception; public Button startButton; public Button cancelButton; public Button exceptionButton; public Scene scene; private View(final Model model) { progressBar = ProgressBarBuilder.create().minWidth(250).build(); title = new Label(); message = new Label(); running = new Label(); state = new Label(); totalWork = new Label(); workDone = new Label(); progress = new Label(); value = new Label(); exception = new Label(); startButton = new Button("Start"); cancelButton = new Button("Cancel"); exceptionButton = new Button("Exception"); final ReadOnlyObjectProperty<Worker.State> stateProperty = model.worker .stateProperty(); progressBar.progressProperty() .bind(model.worker.progressProperty()); title.textProperty().bind(model.worker.titleProperty()); message.textProperty().bind(model.worker.messageProperty()); running.textProperty().bind( Bindings.format("%s", model.worker.runningProperty())); state.textProperty().bind(Bindings.format("%s", stateProperty)); totalWork.textProperty().bind( model.worker.totalWorkProperty().asString()); workDone.textProperty().bind( model.worker.workDoneProperty().asString()); progress.textProperty().bind( Bindings.format("%5.2f%%", model.worker.progressProperty() .multiply(100))); value.textProperty().bind(model.worker.valueProperty()); exception.textProperty().bind(new StringBinding() { { super.bind(model.worker.exceptionProperty()); } @Override protected String computeValue() { final Throwable exception = model.worker.getException(); if (exception == null) return ""; return exception.getMessage(); } }); startButton.disableProperty().bind( stateProperty.isNotEqualTo(Worker.State.READY)); cancelButton.disableProperty().bind( stateProperty.isNotEqualTo(Worker.State.RUNNING)); exceptionButton.disableProperty().bind( stateProperty.isNotEqualTo(Worker.State.RUNNING)); final HBox topPane = HBoxBuilder.create() .padding(new Insets(10, 10, 10, 10)).spacing(10) .alignment(Pos.CENTER).children(progressBar).build(); final GridPane centerPane = GridPaneBuilder .create() .hgap(10) .vgap(10) .padding(new Insets(10, 10, 10, 10)) .columnConstraints( ColumnConstraintsBuilder.create() .halignment(HPos.RIGHT).minWidth(65) .build(), ColumnConstraintsBuilder.create() .halignment(HPos.LEFT).minWidth(200) .build()).build(); centerPane.add(new Label("Title:"), 0, 0); centerPane.add(new Label("Message:"), 0, 1); centerPane.add(new Label("Running:"), 0, 2); centerPane.add(new Label("State:"), 0, 3); centerPane.add(new Label("Total Work:"), 0, 4); centerPane.add(new Label("Work Done:"), 0, 5); centerPane.add(new Label("Progress:"), 0, 6); centerPane.add(new Label("Value:"), 0, 7); centerPane.add(new Label("Exception:"), 0, 8); centerPane.add(title, 1, 0); centerPane.add(message, 1, 1); centerPane.add(running, 1, 2); centerPane.add(state, 1, 3); centerPane.add(totalWork, 1, 4); centerPane.add(workDone, 1, 5); centerPane.add(progress, 1, 6); centerPane.add(value, 1, 7); centerPane.add(exception, 1, 8); final HBox buttonPane = HBoxBuilder.create() .padding(new Insets(10, 10, 10, 10)).spacing(10) .alignment(Pos.CENTER) .children(startButton, cancelButton, exceptionButton) .build(); scene = SceneBuilder .create() .root(BorderPaneBuilder.create().top(topPane) .center(centerPane).bottom(buttonPane).build()) .build(); } } }