I would like to change the cursor to Cursor.WAIT when executing potentially long operations in JavaFX application. I thought that Platform.runLater will help me:
this.getStage().getScene().setCursor(Cursor.WAIT);
Platform.runLater(new Runnable() {
@Override
public void run() {
// Do some stuff
getStage().getScene().setCursor(Cursor.DEFAULT);
}
});
But cursor does not change. Why doesn't this work?
Assuming you are running the following code off of the JavaFX Application thread, a pattern for displaying a wait cursor could be:
Platform.runLater(new Runnable() {
@Override
public void run() {
getStage().getScene().setCursor(Cursor.WAIT);
}
});
// Do some stuff
Platform.runLater(new Runnable() {
@Override
public void run() {
getStage().getScene().setCursor(Cursor.DEFAULT);
}
});
Or, if you are already on the JavaFX application thread, you could use a Service:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.concurrent.*;
import javafx.event.*;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ServiceWithCursorControl extends Application {
private final Button runButton = new Button("Run");
private final Label label = new Label();
private final Service service = new Service() {
@Override
protected Task createTask() {
return new Task<Void>() {
@Override protected Void call() throws Exception {
// do stuff
Thread.sleep(5000);
return null;
}
};
}
};
@Override public void start(Stage stage) {
VBox layout = createLayout();
Scene scene = new Scene(layout, 100, 80);
stage.setScene(scene);
bindUIandService(stage);
stage.show();
}
private void bindUIandService(Stage stage) {
label.textProperty()
.bind(
service.stateProperty().asString()
);
stage.getScene()
.getRoot()
.cursorProperty()
.bind(
Bindings
.when(service.runningProperty())
.then(Cursor.WAIT)
.otherwise(Cursor.DEFAULT)
);
runButton
.disableProperty()
.bind(
service.runningProperty()
);
runButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
service.restart();
}
});
}
private VBox createLayout() {
VBox layout = new VBox(10);
layout.getChildren().setAll(runButton, label);
layout.setPadding(new Insets(10));
layout.setAlignment(Pos.CENTER);
return layout;
}
public static void main(String[] args) {
launch(args);
}
}
It's unclear from your description which approach fits your problem best, but hopefully you can work it out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With