2014-07-24 61 views
1

我今天才剛剛開始學習JavaFX,並試圖通過創建Snake克隆來了解更多信息,但我遇到了線程問題。我想創建一個線程來更新蛇在屏幕上的位置,但不能以普通的Runnable線程方式使用它,因爲我使用該線程內的JavaFX來更新繪製到屏幕上的矩形的位置(我學習了你不能這樣做,而必須使用Tasks,Services,Platform.runLater等)我創建線程的類擴展了JavaFX.scene.layout.Pane,並且我試圖使用一個任務來更新蛇的位置。我的問題是:該任務似乎只運行一次或兩次並退出,沒有給我任何中斷。JavaFX任務結束和JavaFX線程

構造擴展窗格中的類(蛇類擴展集團):

public GameFrame(){ 
    this.setPrefSize(800, 600); 

    Snake snake = new Snake(); 
    this.getChildren().add(snake); 

    taskThread = new Thread(new Task<Void>() { 
     protected Void call() throws Exception { 
       while(!Thread.currentThread().isInterrupted()){ 
        snake.updatePosition(); 
        try{ 
        Thread.sleep(1000); 
        } catch(InterruptedException e){ 
         break; 
        } 
       } 
      return null; 
     } 
    }); 
    taskThread.start(); 
} 

我覺得我並沒有真正掌握什麼是最好的事情在這裏做的,什麼我想做可能是駭人聽聞的。對於我應該做什麼或者我該如何解決這個問題有什麼建議嗎?

回答

4

在JavaFX的線程的基本規則(原諒我,如果你已經瞭解了一些這個,我只想完成)有:

  1. 凡是塊執行(或者需要很長的時間來執行不上FX應用程序線程
  2. 凡是改變Node即應在FX應用程序線程

爲了要執行的場景圖的部分的狀態 - )應在後臺線程中運行幫助實現t JavaFX API提供了一個Task類。這有一個返回值的call()方法;它是Runnable,因此可以作爲參數提供給Thread構造函數,或傳遞給Executor。它還提供有用的回調,保證在FX應用程序線程上執行,例如setOnSucceeded,setOnFailed和各種update...()方法,這些方法在FX應用程序線程上更新諸如progressmessage之類的屬性。

但是,Task類實際上是爲一次性任務設計的:考慮需要從數據庫中檢索數據的應用程序,例如,可能需要一些時間。這些執行特定的操作並返回結果。你的情況有些不同,因爲你的線程正在連續執行。

在這種情況下,最好使用簡單的Thread並使用Platform.runLater(...)來更新UI。 Platform.runLater(...)需要Runnable,並在FX應用程序線程上執行run()方法。

我不清楚爲什麼你的代碼是按照你描述的方式工作的,但假設方法調用snake.updatePosition()導致UI的改變,這應該在FX應用程序線程上執行。在任何情況下,我會嘗試

taskThread = new Thread(new Runnable() { 
    public void run() { 
      while(!Thread.currentThread().isInterrupted()){ 
       Platform.runLater(new Runnable() { 
        @Override 
        public void run() { 
         snake.updatePosition(); 
        } 
       }); 
       try{ 
        Thread.sleep(1000); 
       } catch(InterruptedException e){ 
        break; 
       } 
      } 
    } 
}); 

如果您使用的是Java 8,這一切看起來更好了很多與lambda表達式替換匿名內部類:

taskThread = new Thread(() -> { 
    while (! Thread.currentThread().isInterrupted()) { 
     Platform.runLater(snake::updatePosition); 
     try { 
      Thread.sleep(1000); 
     } catch (InterruptedException exc) { 
      break ; 
     } 
    } 
}); 

一個JavaFX的其他技術,可週期性執行的東西是(ab?)使用動畫:

Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), 
     new EventHandler<ActionEvent>() { 
      @Override 
      public void handle(ActionEvent event) { 
       snake.updatePosition(); 
      } 
     } 
    )); 
    timeline.setCycleCount(Animation.INDEFINITE); 
    timeline.play(); 

或,在Java 8中,稍微光滑

Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), 
     event -> snake.updatePosition())); 
    timeline.setCycleCount(Animation.INDEFINITE); 
    timeline.play();