无法更新GridPane

时间:2012-12-11 12:46:15

标签: multithreading events javafx-2 javafx event-dispatch-thread

我有一个带网格的简单应用程序(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会渲染网格,但不是在每个running之后。我的错误在哪里?如何在每个running之后使FX App Thread渲染我的网格?

更新 得到了解决方案here,但仍然无法完全理解它拒绝工作的原因。

1 个答案:

答案 0 :(得分:1)

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

此外,您的睡眠实际上阻止了事件队列 - 您永远不应该在Thread#sleep(...)内调用Platform#runLater(...)。您实际上阻止了3x1500毫秒的所有事件处理,包括重绘和用户输入。

Thread.sleep()移出Runnable,您将解决这两个问题。事件队列将接收GridChange,有1.5秒更新UI,接收下一个GridChange等等......