JavaFX 同时创建两个阶段

标签 java user-interface javafx javafx-8

我试图在 JavaFX 中同时显示两个阶段,其中第一个阶段应该显示一个进度条,并且应该在第二个阶段准备好显示后立即关闭。 我尝试通过 Platform.runLaterTasks 运行,但问题是两个阶段都被卡住,直到两个阶段都完成加载并且进度条开始动画直到第二个阶段加载完成。

这里是代码的一些摘录:

public void start(Stage primaryStage) throws Exception {
        new Thread(progressTask()).start();
        new Thread(loginTask()).start();
    }



    public Task<Void> loginTask() {
        Task<Void> t = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                Platform.runLater(new Runnable() {

                    @Override
                    public void run() {

                        Stage s = new Stage();
                        FXMLLoader loader = new FXMLLoader(getClass().getResource("Login.fxml"));
                        Scene sc = null;
                        try {

                            sc = new Scene((Parent) loader.load());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                        s.setScene(sc);
                        s.show();

                    }

                });
                return null;
            };
        };
        return t;
    }

    public Task<Void> progressTask() {

        Task<Void> t = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                Platform.runLater(new Runnable() {

                    @Override
                    public void run() {
                            ProgressBar bar = new ProgressBar(0);
                            bar.setPrefSize(200, 24);
                            Timeline task = new Timeline(new KeyFrame(Duration.ZERO, new KeyValue(bar.progressProperty(), 0)), new KeyFrame(
                                    Duration.seconds(5), new KeyValue(bar.progressProperty(), 1)));

                            VBox layout = new VBox(10);
                            layout.getChildren().setAll(bar);
                            Stage stage = new Stage(StageStyle.DECORATED);
                            stage.setScene(new Scene(layout));
                            stage.initModality(Modality.WINDOW_MODAL);
                            stage.show();
                            new Thread() {
                                public void run() {
                                    task.playFromStart();
                                }
                            }.start();
                            task.setOnFinished(new EventHandler<ActionEvent>() {
                                    @Override
                                    public void handle(ActionEvent event) {
                                        stage.close();


                                    }

                                });
                    }
            });
                return null;
        }


};

感谢您的帮助。

最佳答案

您应该创建 Task 来执行长时间运行的操作,并使用回调来更新 UI。很少需要自己调用 Platform.runLater(...)

在您的代码中,Task 根本没有任何作用,因为它们只是安排所有代码在 FX 应用程序线程上使用 Platform.runLater(...)。如此有效,您创建一个新线程只是为了请求在当前线程上执行一些代码。

这是一个示例,可以执行我认为您希望执行的操作:

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class DataLoadingStageExample extends Application {

    @Override
    public void start(Stage primaryStage) {

        Scene scene = buildInitialUI();
        primaryStage.setScene(scene);

        Stage monitorStage = new Stage();

        Task<DataClass> dataLoadingTask = createDataLoadingTask();

        // update UI when dataLoadingTask finishes
        // this will run on the FX Application Thread
        dataLoadingTask.setOnSucceeded(event -> {
            DataClass data = dataLoadingTask.getValue();
            scene.setRoot(createUIFromData(data));
            monitorStage.hide();
        });

        buildProgressUI(monitorStage, dataLoadingTask);

        // manage stage layout:
        primaryStage.yProperty().addListener((obs, oldY, newY) -> monitorStage.setY(newY.doubleValue() - 100));
        primaryStage.setTitle("Application");

        // show both stages:
        monitorStage.show();
        primaryStage.show();

        // start data loading in a background thread:
        new Thread(dataLoadingTask).start();

    }

    private void buildProgressUI(Stage monitorStage,
            Task<?> task) {
        ProgressBar progressBar = new ProgressBar();
        progressBar.progressProperty().bind(task.progressProperty());

        Scene monitorScene = new Scene(new StackPane(progressBar), 400, 75);
        monitorStage.setScene(monitorScene);
        monitorStage.setTitle("Loading progress");
    }

    private Scene buildInitialUI() {
        Label loadingLabel = new Label("Loading...");
        StackPane root = new StackPane(loadingLabel);
        Scene scene = new Scene(root, 600, 400);
        return scene;
    }

    private Task<DataClass> createDataLoadingTask() {
        return new Task<DataClass>() {
            @Override
            public DataClass call() throws Exception {
                // mimic connecting to database
                for (int i=0; i < 100; i++) {
                    updateProgress(i+1, 100);
                    Thread.sleep(50);
                }
                return new DataClass("Data");
            }
        };
    }

    private Parent createUIFromData(DataClass data) {
        // obviously much more complex in real life
        Label label = new Label(data.getData());
        return new StackPane(label);
    }

    public static class DataClass {
        // obviously much more complex in real life
        private final String data ;
        public DataClass(String data) {
            this.data = data ;
        }
        public String getData() {
            return data ;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

关于JavaFX 同时创建两个阶段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27150414/

相关文章:

java - 保存一个表单并在Outputid(主键)中生成一个值,该值一次是另一种表单?

java - 如何使用 EntityManager (JPA) 在 DAO 中实现 update() 方法?

Java 访问者模式 2

javafx - 使用自定义 DatePicker TableCell JavaFX 过滤表时出现问题

java - ArchUnit:检查包是否相互依赖的最优雅的方法

html - 用于 C++ 游戏的精美交互式 GUI

java - XML 或 XUL 是 Java GUI 构建的 future 吗?

html - 如何使用 html 来设置 vb.net 桌面应用程序的样式?

Java - 使程序从文件加载选项的最佳方法是什么?

JavaFX ObservableList 更改不更新 ListView