0

我有一个带有网格 ( GridPane ) 的简单应用程序和一个带有开始/停止按钮的简单工具栏。我的按钮操作如下所示:

startButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent actionEvent) {
            grid.change();
        }
    });

当我点击它时,网格会像它应该的那样改变。因为场景图不是线程安全的并且它仅由 FX 应用程序线程呈现,所以我已经放置了一个应该更新我的网格的服务:

private Service task = new Service(){
    @Override
    protected Task createTask() {
        System.out.println("Task created");
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                for (int i = 0; i < 3; i++) {
                    System.out.println("calling");
                    Platform.runLater(new Runnable(){
                        @Override
                        public void run() {
                            System.out.println("running");
                           grid.changeGeneration();
                            try {
                                Thread.sleep(1500L);
                            } catch (InterruptedException e) {
                                e.printStackTrace();  
                            }
                        }
                    });
                }
                return null;
            }
        };
    }
};

当我运行我的应用程序时,按下按钮后它给了我这个

任务创建 调用 调用 调用 运行 运行 运行

它重新计算网格模型,但它不想渲染视图,实际上网格在所有 Platform.runLater 完成后由 FX App Thread 渲染,但不是在 each 之后running。我的错误在哪里?我怎样才能让 FX App Thread 在每个之后渲染我的网格running

更新:在这里 得到了解决方案,但仍然不能完全理解为什么它拒绝工作。

4

1 回答 1

1

这里的原因很可能是您Runnables连续快速发布了三个,而 FX 队列没有机会在两者之间实际重新绘制。由于没有更好的名称,重绘不会立即执行,而是添加到事件队列的末尾。所以基本上,你的外部循环触发了三个Runnables,事件队列最终看起来像这样:|GridChange|GridChange|GridChange|Repaint|Repaint|Repaint|。

此外,你的 sleep 实际上阻塞了事件队列——你永远不应该Thread#sleep(...)Platform#runLater(...). 您实际上阻止了所有事件处理,包括重绘和用户输入,时间为 3x1500 毫秒。

搬出Thread.sleep()Runnable,你会解决这两个问题。事件队列将接收 GridChange,有 1.5 秒的时间更新 UI,接收下一个 GridChange,依此类推...

于 2012-12-11T18:27:20.527 回答