在 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...
});
我有一项任务是使用线程和 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...
});