JavaFX- new Stage in a task

I want to open a new window from the task but for some reason after line Stage stage = new Stage the code stops executing, but there is no error.

Task<Void> task = new Task<Void>() {

        @Override protected Void call() throws Exception {

            Parent root = FXMLLoader.load(getClass().getResource("sample2.fxml"));
            Stage stage = new Stage();
            System.out.println("Print");
            stage.setTitle("My New Stage Title");
            stage.setScene(new Scene(root, 100, 100));
            stage.show();
            return null;
        }
    };

It never prints out the message 'Print'.

Upvotes: 0

Views: 1112

Answers (2)

Slaw
Slaw

Reputation: 45786

Answer to Question

The reason your Task is failing is because you are creating a Stage on a thread other than the JavaFX Application Thread. The Javadoc of Stage states:

Stage objects must be constructed and modified on the JavaFX Application Thread.

This means when you attempt to create a Stage on the background thread that the Task is running on it will result in an IllegalStateException with a message telling you that you aren't on the JavaFX Application Thread. To solve this issue wrap all code that creates and/or modifies a Stage in a Platform.runLater(Runnable) call.

Side Note: It would probably be better to not create the Stage in the Task at all. Rather, in your case, simply return the result of FXMLLoader.load(URL) and create the Stage when handling the success of the Task.

Task<Parent> task = new Task<Parent>() {
    @Override
    protected Parent call() throws Exception {
        return FXMLLoader.load(getClass().getResource("sample2.fxml"));
    }
};

task.setOnSucceeded(event -> {
    Parent root = task.getValue();
    Stage stage = new Stage();
    stage.setScene(new Scene(root));
    stage.show();
};

Why No Error Shown?

You say there is no error but you also don't show any code that would display an error if one does occurr. When a Task fails it sets the cause of failure in the exception property. To handle the case when a Task fails you can:

  • Listen to the exception property
  • Add an EventHandler to handle a WorkerStateEvent.WORKER_STATE_FAILED event and query the exception property
    • Either using task.setOnFailed(EventHandler) or task.addEventXXX(EventType, EventHandler) where XXX is either Filter or Handler
  • Override the protected void failed() method in your Task implementation and query the exception property
    • The failed() method will always be called on the JavaFX Application Thread
  • Catch and handle the exception in the call() method before re-throwing it
  • Possibly other ways I'm not currently thinking of

Upvotes: 1

You need an Executor to start the thread

Executor exec = Executors.newCachedThreadPool(runnable -> {
    Thread t = new Thread(runnable);
    t.setDaemon(true);
    return t;
});

exec.execute(task);

Upvotes: 0

Related Questions