2015-12-07 101 views
1

我有一個使用線程和JavaFX庫的任務。單獨的線程1需要通過按下按鈕來啓動。該線程應該用一個小的間隔(例如5毫秒)滿足整數值(100-150)的列表。在JavaFX中創建和停止線程

並且在生成值後,它應該停止。新的線程2必須啓動並用生成的值填充ViewList。

但我每次都得到一個異常,當一個新的值被線程1添加到我的清單:

Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4 
    at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204) 
    at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364) 
    at javafx.scene.Scene.addToDirtyList(Scene.java:485) 
    at javafx.scene.Node.addToSceneDirtyList(Node.java:424) 
    at javafx.scene.Node.impl_markDirty(Node.java:415) 

我試着在按鈕事件偵聽器來使用Platform.runLater(),而不是創建一個新的線程,但是程序在這種情況下停止響應。

任何人都可以請幫助我,如何在一個單獨的線程中填充值的集合,以及如何在第一個線程完成後如何啓動第二個更新ViewList元素?

這裏是我的類:

int itemName = 100; 
Button btnOne = new Button("Button one"); 
Label label = new Label("Press the button to start"); 

ObservableList<String> listOptions = FXCollections.observableArrayList(); 
ListView<String> list; 

@Override 
public void start(Stage primaryStage) throws Exception{ 
    primaryStage.setTitle("Hurry"); 

    list = new ListView<>(listOptions); 
    list.setPrefSize(120, 120); 

    MultipleSelectionModel<String> lvSelModel = 
      list.getSelectionModel(); 

    FlowPane rootNode = new FlowPane(10, 10); 
    rootNode.setAlignment(Pos.CENTER); 

    Scene myScene = new Scene(rootNode, 180, 200); 
    primaryStage.setScene(myScene); 

    lvSelModel.selectedItemProperty().addListener(
     (changed, oldValue, newValue) -> { 
     label.setText("List option selected: " + newValue); 
    }); 

    rootNode.getChildren().addAll(btnOne, list, label); 
    primaryStage.show(); 

    Task<Integer> threadOne = new Task<Integer>(){ 
     @Override 
     protected Integer call() throws Exception{ 

      while(itemName < 130){ 
       final int finalValue = itemName++; 
       listOptions.add(String.valueOf(itemName)); 
       Platform.runLater(
       () -> label.setText("Generating: " + finalValue)); 
       Thread.sleep(100); 
      } 
      label.setText("Thread 1 finished"); 
      return itemName; 
     } 
    }; 

    btnOne.setOnAction( 
     ae -> { 
     Thread th = new Thread(threadOne); 
     th.setDaemon(true); 
     th.start(); 
    }); 

} 

public static void main(String[] args) { 
    launch(args); 
}}` 

結果的程序應該是這樣的:

謝謝大家對你的時間!

回答

2

由於listOptions是列表視圖中的項目列表,調用listOptions.add(...)會修改UI(列表視圖)。因此需要在FX應用程序線程上執行,與設置標籤的文本類似。只是移動該行於側Platform.runLater(...)

Task<Integer> threadOne = new Task<Integer>(){ 
    @Override 
    protected Integer call() throws Exception{ 

     while(itemName < 130){ 
      final int finalValue = itemName++; 
      Platform.runLater(() -> { 
       listOptions.add(String.valueOf(itemName)); 
       label.setText("Generating: " + finalValue); 
      }); 
      Thread.sleep(100); 
     } 
     label.setText("Thread 1 finished"); 
     return itemName; 
    } 
}; 

要開始另一項任務(或者更確切地說,做任何事情),當第一個任務完成後,使用任務的onSucceeded處理程序:

threadOne.setOnSucceeded(e -> { 
    // create another task and run it in another thread... 
}); 
+0

謝謝!!你幫了很多! – BohdanN