Skip to content

Instantly share code, notes, and snippets.

@TheItachiUchiha
Created June 10, 2015 12:38
Show Gist options
  • Save TheItachiUchiha/06bdf4ad3039616834a1 to your computer and use it in GitHub Desktop.
Save TheItachiUchiha/06bdf4ad3039616834a1 to your computer and use it in GitHub Desktop.
ComboSample
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.concurrent.Task;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Steps to reproduce issues:
* 1. Select "DEV" from first dropdown - it will run for 20s
* 2. Immediately select "TEST" from 2nd dropdown - it will run for 5s
*
* Expected result
* 1. Cursor remains WAIT until both tasks have completed
* 2. When both tasks have completed Cursor should remain at DEFAULT
* when placed over 2nd comboxbox drop down
*
* Actual result
* 1. Cursor changes to DEFAULT before 1st task has completed
* 2. (Intermittent): After both tasks have completed, clicking on 2nd combo
* and placing mouse pointer over dropdown list, causes cursor to change
* back to WAIT.
*/
public class ComboSample extends Application {
public static void main(String[] args) { launch(args); }
private final ExecutorService pool = Executors.newFixedThreadPool(4);
final ObjectProperty<Cursor> CURSOR_DEFAULT = new SimpleObjectProperty<>(Cursor.DEFAULT);
final ObjectProperty<Cursor> CURSOR_WAIT = new SimpleObjectProperty<>(Cursor.WAIT);
@Override public void start(final Stage primaryStage) {
primaryStage.setTitle("Combo Sample");
Label label1 = new Label();
Label label2 = new Label();
ComboBox<String> from = new ComboBox<>();
from.getItems().addAll("DEV", "TEST", "PROD");
from.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
pool.submit(task1);
label1.textProperty().bind(task1.messageProperty());
});
ComboBox<String> to = new ComboBox<>();
to.getItems().addAll("DEV", "TEST", "PROD");
to.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
pool.submit(task2);
label2.textProperty().bind(task2.messageProperty());
});
HBox layout = new HBox(10);
layout.getChildren().addAll(new VBox(from, label1), new VBox(to, label2));
primaryStage.setScene(new Scene(layout));
primaryStage.setWidth(400);
primaryStage.setHeight(200);
primaryStage.show();
primaryStage.getScene().cursorProperty().bind(Bindings.when(Bindings.or(task1.runningProperty(), task2.runningProperty()))
.then(CURSOR_WAIT).otherwise(CURSOR_DEFAULT));
primaryStage.setOnCloseRequest(event -> {
pool.shutdownNow();
});
}
Task<Void> task1 = new Task<Void>() {
@Override protected Void call() throws Exception {
System.out.println("selectFrom - Start");
for(int i=1; i<=20; i++) {
updateMessage(String.valueOf(i));
Thread.sleep(1000);
}
System.out.println("selectFrom - End");
return null;
}
};
Task<Void> task2 = new Task<Void>() {
@Override
protected Void call() throws Exception {
System.out.println("selectTo - Start");
for(int i=1; i<=5; i++) {
updateMessage(String.valueOf(i));
Thread.sleep(1000);
}
System.out.println("selectTo - End");
return null;
}
};
}
@shnplr
Copy link

shnplr commented Jun 11, 2015

Thanks for this. Note as Task is a one-shot class the selection event wont run a 2nd time - also is it possible to bind dynamically if we don't define all the tasks up front? I'm looking for a solution where I can pass any task through this Cursor.WAIT pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment