所以我得到了一个相当简单的JavaFX应用程序,在按下开始按钮时创建并启动2个线程。我还有一个重置按钮,它应该中断线程并清除GUI组件。这似乎工作正常。然后我应该能够按下重置按钮然后再次启动按钮创建2个线程并再次启动它们。这也有效。当这些线程正在执行时,它们正在使用我的回调,将字符串返回给我的Controller类,然后将其添加到listview中。这在我第一次运行应用程序时工作正常,但如果我按清除然后启动,则在向列表视图添加数据时回调会引发错误。 java.lang.IllegalStateException: Not on FX application thread
据我所知,每当除了main之外的其他一些线程尝试更改fx元素时,都会抛出此内容。但是为什么我第一次点击开始时工作正常,但是没有点击清除然后重新开始?这是我的代码:
/**
* Controls GUI and start threads..
*
*
*/
public class Controller implements Initializable {
@FXML
private Button btnRun;
@FXML
private Button btnReset;
@FXML
private TextArea taInput;
@FXML
private ListView<String> lwProducer;
@FXML
private ListView<String> lwConsumer;
private boolean sync;
private Buffer buffer;
private ObservableList<String> conData;
private ObservableList<String> proData;
private Thread consumerThread;
private Thread producerThread;
private Runnable producerR;
private Runnable consumerR;
/**
* Initializes elements, sets an initial value for the textbox.
*/
public void initialize(URL location, ResourceBundle resources) {
taInput.setText("The quick brown\nfox jumps over\nthe lazy dog");
btnReset.setDisable(true);
btnRun.setDefaultButton(true);
lwProducer.setStyle("-fx-focus-color: transparent;");
lwConsumer.setStyle("-fx-focus-color: transparent;");
}
/**
* Eventhandler for btnRun that will start new threads.
*
* @param e
*/
@FXML
protected void btnRun(ActionEvent e) {
System.out.println(sync);
conData = FXCollections.observableArrayList();
proData = FXCollections.observableArrayList();
buffer = new Buffer();
producerR = new Producer(new ProducerCB(), buffer, taInput.getText());
consumerR = new Consumer(new ConsumerCB(), buffer);
producerThread = new Thread(producerR);
consumerThread = new Thread(consumerR);
producerThread.start();
consumerThread.start();
btnRun.setDisable(true);
taInput.setDisable(true);
btnReset.setDisable(false);
}
/**
* Eventhandler for btnReset. If pressed, threads and all gui components
* will be cleared.
*
* @param e
*/
@FXML
protected void btnReset(ActionEvent e) {
System.out.println("Resetting");
producerThread.interrupt();
consumerThread.interrupt();
producerThread = null;
consumerThread = null;
lwProducer.getItems().clear();
lwConsumer.getItems().clear();
conData = null
proData = null
producerR = null;
consumerR = null;
btnRun.setDisable(false);
taInput.setDisable(false);
btnReset.setDisable(true);
}
/**
* Callback for producer thread. Updates the left hand listview with added
* data.
*
*
*/
private class ProducerCB implements Callback {
@Override
public void returnData(String str) {
proData.add(str);
lwProducer.setItems(proData);
}
}
/**
* Callback for consumer thread. Updates the right hand listview with read
* data.
*
*/
private class ConsumerCB implements Callback {
@Override
public void returnData(String str) {
conData.add(str); // Throws exception!!!!!!!
lwConsumer.setItems(conData);
}
}
}
堆栈跟踪
Exception in thread "Thread-7" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-7
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
at com.sun.javafx.scene.control.skin.ListCellSkin.handleControlPropertyChanged(ListCellSkin.java:49)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.scene.control.Labeled.setText(Labeled.java:145)
at com.sun.javafx.scene.control.skin.ListViewSkin$2.updateItem(ListViewSkin.java:319)
at javafx.scene.control.ListCell.updateItem(ListCell.java:471)
at javafx.scene.control.ListCell.lambda$new$160(ListCell.java:167)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:155)
at java.util.AbstractList.add(AbstractList.java:108)
at assignment2.Controller.addData(Controller.java:163)
at assignment2.Controller.access$2(Controller.java:162)
at assignment2.Controller$ConsumerCB.returnData(Controller.java:158)
at assignment2.Consumer.run(Consumer.java:22)
at java.lang.Thread.run(Thread.java:745)
答案 0 :(得分:6)
与AWT事件调度程序线程类似,只能在使用Java FX应用程序线程时更新JavaFx UI组件。
有关此主题的进一步阅读,请参阅here。解决此类问题的一种方法是使用Platform.runLater()。
答案 1 :(得分:0)
根据Stacktrace,你在非fx线程中改变一些fx元素的值(称为&#34; Thread-7“,显然这是你创建的匿名线程)。我想你可以在conData.add(str)中设置断点并查看调用层次结构。您可以找到自己的根本原因。