I am trying to provide feedback in a JavaFX 8 application when a user chooses a menu item that launches a blocking process in another thread. In my real application it's a file download, but I have created a test case using minimal code by way of example:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.MenuButton;
import javafx.scene.control.ToolBar;
import javafx.scene.control.MenuItem;
import javafx.stage.Stage;
public class BlockingThreadTestCase extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
MenuItem menuItem = new MenuItem("Start");
MenuButton menuButton = new MenuButton();
menuButton.setText("Async Process");
menuButton.getItems().addAll(menuItem);
menuItem.setOnAction(event -> {
menuButton.setText("Running...");
Platform.runLater(() -> {
try {
// Simulate a blocking process
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
menuButton.setText(menuButton.getText() + "Done!");
});
});
final ToolBar toolbar = new ToolBar(menuButton);
final Scene scene = new Scene(toolbar);
primaryStage.setScene(scene);
primaryStage.setWidth(150);
primaryStage.show();
}
}
Here's how it's supposed to work: When you select the "Start" menu item, the main menu text should immediately change to "Running...", and then it should append "Done!" after the 5-second sleep that simulates my file download.
What is actually happening is both text updates are firing after the blocking process is done, even though I'm using Platform.runLater()
. What am I doing wrong?