问题
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'.
回答1:
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 aWorkerStateEvent.WORKER_STATE_FAILED
event and query theexception
property- Either using
task.setOnFailed(EventHandler)
ortask.addEventXXX(EventType, EventHandler)
whereXXX
is eitherFilter
orHandler
- Either using
- Override the
protected void failed()
method in yourTask
implementation and query theexception
property- The
failed()
method will always be called on the JavaFX Application Thread
- The
- Catch and handle the exception in the
call()
method before re-throwing it - Possibly other ways I'm not currently thinking of
回答2:
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);
来源:https://stackoverflow.com/questions/50730335/javafx-new-stage-in-a-task