我可以访问从非JavaFX线程更新(添加,删除元素)的ObservableList<T>
,我在ListView<T>
中显示。
如果列表只是在UI中显示它会抛出java.lang.IllegalStateException: Not on FX application thread;
,所以我的解决方案是在UI线程中创建第二个列表并监听更改并更新UI线程中的第二个列表:
ObservableList<Person> secondList = FXCollections.observableArrayList();
secondList.addAll(originalList);
originalList.addListener((ListChangeListener<? super Person>)change-> {
while(change.next()) {
if (change.wasRemoved()) {
Platform.runLater(() -> secondList.subList(change.getFrom(), change.getFrom() + change.getRemovedSize()).clear());
}
if (change.wasAdded()) {
Platform.runLater(() -> secondList.addAll(change.getFrom(), change.getAddedSubList()));
}
}
});
ListView<Person> listViewPerson = new ListView<>(secondList);
我认为这应该可以正常工作(如果有任何问题,请指出它们,我忽略了问题简单的排列)。
但是,当列表中有一个提取器时会出现问题:
ObservableList<Person> secondList = FXCollections.observableArrayList(person -> new Observable[]{person.adultProperty()});
对成人属性的更改发生在非javafx线程上,显然会抛出相同的异常或导致一些未定义的UI行为。
我已经考虑过2个解决这个问题的方法:
1)创建原始类的UI等效类并在UI线程中更新其“属性:
public PersonUI(Person person) {
adult = new SimpleBooleanProperty(person.isAdult());
person.adultProperty().addListener((observableValue, oldValue, newValue) -> {
Platform.runLater(() -> this.adult.set(newValue));
});
}
并在界面显示PersonUI
而不是Person
。
不要认为这是必要的,但这里是此解决方案的完整代码:https://pastebin.com/FYXrre6U
2)使用Platform.runLater()
还有其他解决方案吗?如果我目前的解决方案有任何问题,请指出。
答案 0 :(得分:1)
选项3:实现将所有更改传播到fx-thread的transformationList。这是一项前期工作,但可以重复使用。
大纲(未经过正式测试和不完整!)
/**
* A 1:1 transform of the sourceList that guarantees to fire change notification
* on the fx-thread.
*
* @author Jeanette Winzenburg, Berlin
*/
public class FXThreadTransformationList<E> extends TransformationList<E, E> {
public FXThreadTransformationList(ObservableList<E> source) {
super(source);
}
@Override
protected void sourceChanged(Change<? extends E> c) {
beginChange();
while (c.next()) {
if (c.wasPermutated()) {
// tbd
} else if (c.wasUpdated()) {
update(c);
} else if (c.wasReplaced()) {
// tbd
} else {
addedOrRemoved(c);
}
}
// commit on fx-thread
endChangeOnFXThread();
}
public void endChangeOnFXThread() {
Platform.runLater(() -> endChange());
}
private void addedOrRemoved(Change<? extends E> c) {
if (c.wasRemoved()) {
nextRemove(c.getFrom(), c.getRemoved());
} else if (c.wasAdded()) {
nextAdd(c.getFrom(), c.getTo());
} else {
throw new IllegalStateException("expected either removed or added, but was:" + c);
}
}
private void update(Change<? extends E> c) {
for (int pos = c.getFrom(); pos < c.getTo(); pos++) {
nextUpdate(pos);
}
}
@Override
public int getViewIndex(int index) {
return index;
}
@Override
public int getSourceIndex(int index) {
return index;
}
@Override
public E get(int index) {
return getSource().get(index);
}
@Override
public int size() {
return getSource().size();
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(FXThreadTransformationList.class.getName());
}