2017-10-28 187 views
2

最近幾天我一直在使用JavaFX,FXML,任務和屬性進行實驗。我偶然發現了一種奇怪的行爲,希望你能幫助我更好地理解發生了什麼。JavaFX:僅在更新標籤時才應用線程JavaFX?

我有一個簡約的GUI,看起來像這樣:GUI

如果我按一下按鈕創建並啓動了新的任務。此任務將增加一個雙重屬性,並將新值寫入標籤並在ProgressBar中進行設置。任務的代碼可以在這裏看到:

public class TestTask extends Task<Void>{ 

    private final DoubleProperty doubleValue = new SimpleDoubleProperty(); 

    @Override 
    protected Void call() throws Exception { 
     for(double i = 0.1; i <= 1; i = i+0.1) { 
      doubleValue.set(i); 
      Thread.sleep(1000); 
     } 
     return null; 
    } 

    public DoubleProperty test() { 
     return doubleValue; 
    } 
} 

的FXML控制器的代碼如下:

public class FXMLDocumentController implements Initializable { 

    @FXML private Label label; 
    @FXML private Slider slider; 

    //Called when the Button is clicked 
    @FXML 
    private void handleButtonAction(ActionEvent event) { 
     TestTask task = new TestTask(); 
     task.test().addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> { 
      //Works without problems 
      slider.setValue(newValue.doubleValue()); 
      //Throws an exception 
      label.setText("Value" + newValue.doubleValue()); 
     }); 
     new Thread(task).start(); 
    } 
} 

如果我運行這段代碼試圖更新以下異常標籤結果:java.lang.IllegalStateException:不在FX應用程序線程上; currentThread =線程4。滑塊的更新工作正常,並沒有拋出任何東西。

閱讀SO下列問題後:

我明白,因爲我試圖內執行UI更新標籤的更新失敗Listener從TestTask線程調用,而不是從FXApplication線程調用。

我的問題是:爲什麼更新的滑塊工作和不會引發異常?更新在Listener內進行,因此在TestTask Thread內進行。不應該這個嘗試還會拋出「不在FX應用程序線程」異常?

在此先感謝您花時間幫助我。

+3

有時會檢查線程,有時不會。它不一致。儘管如此,場景中的節點應該從應用程序線程更新... – fabian

+0

@fabian但看到這樣的行爲仍然很奇怪。即使我減少TestTask內的睡眠時間並增加迭代次數,每次都能順利進行。當然,每個UI更新都必須在JavaFX線程內,但這種情況仍然很有趣。我會看看滑塊課,也許我會在那裏找到答案。 – JKostikiadis

回答

3

在您偵聽另一個線程上的屬性更改時更新一個線程上的屬性只是一個race condition。不要這樣做。

不僅JavaFX系統假定更新的UI發生在單個線程上,它也假定對屬性相同,無論它們是否綁定到UI元素。不要依賴JavaFX系統來檢查所有競爭條件,併爲您正確報告和處理它們,因爲它不是爲了這樣做而設計的。

您需要編寫您的代碼,以防止出現這種情況。