对于小型 FXML,Sebastian 的解决方案很好,但如果您在打开弹出窗口时遇到冻结,可能是 FXML 太大或者您正在通过网络加载它。在这种情况下,FXMLLoader 将阻止您的 GUI,因此您需要在后台执行 FXMLLoader。您可以使用为您的场景返回父级的服务,并在服务完成后创建场景和舞台。
这是一个完整的例子:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage stage) throws Exception {
VBox vbox = new VBox(10);
vbox.setAlignment(Pos.CENTER);
final ProgressIndicator progress = new ProgressIndicator(-1);
progress.setVisible(false);
Button button = new Button("Open fxml");
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
final Service<Parent> service = new Service<Parent>() {
@Override
protected Task<Parent> createTask() {
return new Task<Parent>() {
@Override
protected Parent call() throws Exception {
//Out of FX Thread
String fxml = "/FxmlTest.fxml";
Parent root = FXMLLoader.load(getClass().getResource(fxml));
return root;
}
};
}
};
progress.visibleProperty().bind(service.runningProperty());
service.start();
service.runningProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> value, Boolean oldValue, Boolean newValue) {
if(!newValue){//The service has ended
//In the FX Thread
Stage stage = new Stage();
Scene scene = new Scene(service.getValue());
stage.setScene(scene);
stage.show();
}
}
});
}
});
vbox.getChildren().addAll(button, progress);
Scene scene = new Scene(vbox);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我放置了一个进度指示器来显示该服务在加载时可能需要一些时间。
如果你想检查它在 FX Thread 中的位置,你只需要使用 Platform.isFxApplicationThread()。
希望能帮助到你。