在JavaFX中使用线程手动更新ListView

时间:2018-12-09 09:45:54

标签: java multithreading sockets listview javafx

我正在开发邮箱,我希望客户端自动检查是否有新电子邮件。我通过使用一个循环直到关闭客户端的线程来完成此操作,如果发现列表中的当前电子邮件数量与服务器上的文件数量不同,它将重新加载数据并添加新电子邮件。它有效,但是每次列表上有更新时,都会出现此异常:

Exception in thread "Thread-5" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-5
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:279)
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 mailbox.ListController$1.updateItem(ListController.java:56)
at mailbox.ListController$1.updateItem(ListController.java:49)
at javafx.scene.control.ListCell.updateItem(ListCell.java:471)
at javafx.scene.control.ListCell.access$300(ListCell.java:72)
at javafx.scene.control.ListCell$2.changed(ListCell.java:185)
at javafx.scene.control.ListCell$2.changed(ListCell.java:175)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(ObjectPropertyBase.java:105)
at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
at javafx.scene.control.ListView.setItems(ListView.java:390)
at mailbox.ListController$2.run(ListController.java:71)

这是我的ListView Controller代码:

public class ListController {

@FXML
private ListView<Email> listView;
private DataModel model;
private int NoE;

public void initModel(DataModel model) throws IOException, ClassNotFoundException, ParseException {
    if (this.model != null) {
        throw new IllegalStateException("Model can only be initialized once");
    }
    this.model = model;

    model.loadData();

    listView.setItems(model.getEmailList());

    listView.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection)
            -> model.setCurrentEmail(newSelection));
    model.currentEmailProperty().addListener((obs, oldEmail, newEmail) -> {
        if (newEmail == null) {
            listView.getSelectionModel().clearSelection();
        } else {
            listView.getSelectionModel().select(newEmail);
        }
    });

    listView.setCellFactory(lv -> new ListCell<Email>() {
        @Override
        public void updateItem(Email mail, boolean empty) {
            super.updateItem(mail, empty);
            if (empty) {
                setText(null);
            } else if (mail != null) {
                setText(mail.getMittente());
            }
        }
    });

    NoE = model.getNumberOfEmail();
    new Thread() {
        @Override
        public void run() {
            while (true) {
                try {
                    int current = model.askNumbOfEmail();
                    if (NoE != current) {
                        NoE = current;
                        model.reLoadData();
                        listView.setItems(model.getEmailList());
                    }
                } catch (IOException ex) {
                    Thread.currentThread().interrupt();
                    return;
                } catch (ParseException ex) {
                    System.out.println("ParseException ERROR!");
                }
            }
        }
    }.start();
  }
}

1 个答案:

答案 0 :(得分:2)

您需要输入这一行

 listView.setItems(model.getEmailList());

Platform.runLater内部:

 Platform.runLater(() -> listView.setItems(model.getEmailList()));