0

我有一個簡單的應用程序與網格(GridPane)和一個簡單的工具欄與開始/停止按鈕。我的按鈕動作看起來像這樣:無法更新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之後渲染。我的錯誤在哪裏?我該如何讓FX應用程序線程在每個running之後渲染我的網格?

UPDATE: 得到了解決here,但仍不能完全理解爲什麼它拒絕工作。

回答

1

這裏的原因很可能是您快速連續發佈了三個Runnables,並且FX隊列沒有得到實際重新繪製的機會。 因爲缺少更好的名稱,重繪不會立即執行,而是會添加到事件隊列末尾。所以基本上,你的外層循環觸發了三個Runnables,事件隊列最終看起來像這樣:| GridChange | GridChange | GridChange | Repaint | Repaint | Repaint |。

此外,你的睡眠實際上是阻塞事件隊列 - 你永遠不應該在Platform#runLater(...)範圍內調用Thread#sleep(...)。您實際上阻止了3x1500毫秒的所有事件處理,包括重繪和用戶輸入。

Thread.sleep()移出Runnable,您將解決這兩個問題。事件隊列將收到GridChange,有1.5秒更新用戶界面,接收下一個GridChange等...

+0

我試圖把Thread.sleep()放在Task.call()中,那也沒有幫助。 – 4lex1v