在 JavaFX 中创建和停止线程

Creating and stopping threads in JavaFX

我有一项任务是使用线程和 JavaFX 库。一个单独的线程 1 需要通过按下一个按钮来启动。该线程应该以较小的间隔(例如 5 毫秒)完成一个整数值 (100 - 150) 的列表。

生成值后,它应该停止。新线程 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 元素?

这是我的 class:

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);
}}`   

结果程序应该是这样的:

感谢大家抽出宝贵时间!

因为 listOptions 是列表视图中的项目列表,调用 listOptions.add(...) 修改 UI(列表视图)。因此需要在 FX Application Thread 上执行,类似于设置标签的文本。只需将那条线移到 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...
});