【问题标题】:JavaFX Update Issue?JavaFX 更新问题?
【发布时间】:2018-09-24 08:47:14
【问题描述】:

我正在使用 JavaFX 开发游戏,现在我正在尝试创建一个加载屏幕,因为加载资产需要一些时间。我创建了一个显示多个进度条的 LoadingPane 类,我确信它可以工作。但是,在下面的代码中,加载窗格在 loadAssets 函数之后才会可见,即使我事先添加了它。当我运行下面的代码时,我会看到一个空白阶段,显示资产加载所需的时间,然后是一个带有已完成进度条的屏幕。

我找不到任何有类似问题的人,或者任何类型的刷新或更新功能来强制场景在继续程序之前显示加载窗格。

注意:我删除了一些设置键盘输入处理的无关代码。

public class Main extends Application{
    Pane root = new Pane();
    Scene mainScene = new Scene(root, Constants.WINDOW_WIDTH, Constants.WINDOW_HEIGHT, Color.BLACK);

    static LoadingPane loadingPane  = new LoadingPane(3);
    private static int loadingIndex = 0;

    public static void main(String[] args) {
        if(Constants.DEBUG_MODE)
            System.out.println("WARNING: Game has launched in debug mode!");
        launch(args);
    }

    public static void updateProgress(double percent){
        loadingPane.setBarLength(loadingIndex, percent);
    }

    public static void loadAssets(){
        RoomLoader.createRooms();
        updateProgress(1.0);
        loadingIndex++;

        ProjectileLoader.load("imgs/projectiles/");
        ProjectileLoader.load(Constants.BATTLE_IMAGES_FILEPATH);
        updateProgress(1.0);
        loadingIndex++;

        BattleLoader.createBattles();
        updateProgress(1.0);
        loadingIndex++;
    }
    public static void updateProgress(double percent){
        loadingPane.setBarLength(loadingIndex, percent);
    }

    @Override
    public void start(final Stage primaryStage) {

        //root.getChildren().add(new javafx.scene.image.ImageView(new Image("imgs/loading.png")));
        root.setLayoutX(0);

        primaryStage.setScene(mainScene);
        primaryStage.show();
        primaryStage.toFront();

        primaryStage.setTitle("Branch");
        primaryStage.setResizable(false);
        //primaryStage.getIcons().add(new Image("core/imgs/soul/red.png"));
        //This allows the closing of the primaryStage to end the program
        primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>(){
            @Override
            public void handle(WindowEvent t) {
                System.exit(0);
            }
        });

        root.resize(Constants.WINDOW_WIDTH, Constants.WINDOW_HEIGHT);
        primaryStage.getIcons().add(new Image("imgs/icon.png"));

       //End GUI setup

        //The problem lines
        root.getChildren().add(loadingPane);
        //refresh root?
        loadAssets();
    }
}

编辑:工作代码 对于遇到类似问题的任何人,以下是我用来使其工作的代码:

我替换了这个:

//The problem lines
root.getChildren().add(loadingPane);
//refresh root?
loadAssets();

有了这个:

root.getChildren().add   (loadingPane);

Task<Integer> loadingTask = new Task<Integer>() {
    @Override protected Integer call() throws Exception {
        loadAssets();

        return 1;
    }
};

loadingTask.setOnSucceeded(new EventHandler<WorkerStateEvent>(){
    @Override
        public void handle(WorkerStateEvent t){
            loadingPane.setVisible(false);
            load(); //note: this function sets up the actual game
                    //updating the GUI, adding game elements, etc
        }
    });


new Thread(loadingTask).start();

我不能说这是解决此问题的最佳方法,但我可以说它有效。祝你好运!

【问题讨论】:

  • 您需要在单独的线程中运行更新方法。
  • 成功了,谢谢!你知道是什么原因造成的吗?
  • 嗯。我认为代码的工作方式是[一些代码 -> 调用更新 GUI -> GUI 更新 -> 回到你在代码中的位置]。这不是 FX 的工作原理吗?
  • 我添加了一个答案,您可以选择它作为接受的答案。

标签: java javafx refresh


【解决方案1】:

JavaFX 应用程序在称为 Application Thread 的特定线程上运行,或者在执行一些昂贵的操作时使 GUI 响应,例如在您的情况下加载资产,您需要在您自己创建的另一个 Thread 上加载资产,或者您可以使用Task,这是用于此类用例的JavaFX 类之一。

我建议您阅读official javadocs中的Task

【讨论】:

  • 谢谢,我不知道 FX 是这样工作的。我假设一切都在同一个线程上运行。这就解释了为什么在主类中需要一个 start 函数。谢谢!
  • Rip,当您在 cmets 中回答但其他人先回答时,您的回答排在第二位
  • @JacobB。我不想争论,但我没有偷你的答案,你只是说他需要另一个部分正确的线程,最重要的是你没有任何解释原因。
  • 那是有效的。我也不想争论。享受你的成功。
  • 另外我从没提过偷你的答案
【解决方案2】:

更新方法需要一个单独的线程。

代码以线性方式运行,一个代码运行然后下一个。使用单独的线程,两行代码可以并排运行。进程运行,同时 GUI 更新。

【讨论】:

    猜你喜欢
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-07
    • 2018-04-06
    • 2014-12-20
    • 2016-11-15
    • 2020-11-09
    相关资源
    最近更新 更多