JAVAFX : why wait cursor needs a new thread?

Without the threads, your code is being executed on the FX Application Thread. This is the thread that is (effectively) responsible for rendering the UI to the screen and for processing user input. If you execute a long-running task on this thread, then you prevent any of the normal functionality of the FX Application Thread from occurring until your long-running task is complete. In particular, if you do

scene.setCursor(Cursor.WAIT);
longRunningTask();
scene.setCursor(Cursor.DEFAULT);

then the settings take place in the order you specify, but the scene does not get rerendered until all lines of code are complete. Hence you never actually see any changes to the UI – including the change to the cursor – until after your code is complete. The next time the FX Application Thread has an opportunity to render the scene, the cursor is set to Cursor.DEFAULT, and you never see the wait cursor.

There are two basic rules for multithreading and JavaFX (and the same rules generally apply to most UI toolkits):

  1. Any changes to the UI must be performed on the FX Application Thread
  2. Long-running processes should not be performed on the FX Application Thread (as they make the UI unresponsive)

So your solution is not actually correct, because you violate both of those rules. You should

  1. Set the cursor to WAIT on the FX Application Thread
  2. Start your long running task on a background thread
  3. When the task is complete, set the cursor back to DEFAULT, on the FX Application Thread.

You can do this using a Task:

scene.setCursor(Cursor.WAIT);
Task<Void> task = new Task<Void>() {
    @Override
    public Void call() {
        // long running task here...
        return null ;
    }
};
task.setOnSucceeded(e -> scene.setCursor(Cursor.DEFAULT));
new Thread(task).start();

Leave a Comment