自定义 Observable List 实现,通知消费者变化
Custom Observable List implementation, notifying consumers of changes
我已经为 TreeItems 列表创建了自定义 ObservableList 实现。我的自定义实现可以从我的应用程序内部监听各种通知(使用 OSGi EventAdmin),并相应地更新自身。然后我希望它的消费者(一个 TreeView 小部件)随着列表的更改而更新。但是,我看不到如何通知消费者。
在 ObservableList 子类中,我正在实现 addListener(ListChangeListener),我希望在将对象添加到小部件时调用它。然而,它从未被调用过;我没有听众,因此没有明显的方式在列表更改时通知任何人。我一定是遗漏了什么。
这是我的 TreeItem 实现的一个片段,returns 我的 ObservableList 实例响应 getChildren 调用:
@Override
public ObservableList<TreeItem<DataObject>> getChildren() {
if (needChildren) {
needChildren = false;
children = new MyObservableList();
}
return children;
}
这是我的自定义 ObservableList 实现的简化版本,它简单地包装了一个 FXCollections.observableArrayList 并添加了一个 OSGi 事件处理程序。我收听内部列表中的更改,以便我可以将这些更改传递给我的听众。
public class MyObservableList implements ObservableList<TreeItem<DataObject>>, EventHandler {
private List<ListChangeListener<? super TreeItem<DataObject>>> changeListeners = new ArrayList<>();
private List<InvalidationListener> invalidationListeners = new ArrayList<>();
private ObservableList<TreeItem<DataObject>> theList;
private int size;
public MyObservableList() {
theList = FXCollections.observableArrayList();
theList.addListener(new ListChangeListener<TreeItem<DataObject>>() {
@Override
public void onChanged(Change<? extends TreeItem<DataObject>> change) {
fireValueChangedEvent(change);
}
});
}
@Override
public int size() {
return theList.size();
}
@Override
public boolean isEmpty() {
return (size == 0);
}
@Override
public boolean contains(Object o) {
return theList.contains(o);
}
@Override
public Iterator iterator() {
return theList.iterator();
}
@Override
public boolean remove(Object o) {
return theList.remove(o);
}
@Override
public boolean addAll(Collection c) {
return theList.addAll(c);
}
@Override
public boolean addAll(int index, Collection c) {
return theList.addAll(index, c);
}
@Override
public void clear() {
theList.clear();
}
@Override
public TreeItem<DataObject> get(int index) {
return theList.get(index);
}
@Override
public int indexOf(Object o) {
return theList.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return theList.lastIndexOf(o);
}
@Override
public ListIterator listIterator() {
return theList.listIterator();
}
@Override
public ListIterator listIterator(int index) {
return theList.listIterator(index);
}
@Override
public List<TreeItem<DataObject>> subList(int fromIndex, int toIndex) {
return theList.subList(fromIndex, toIndex);
}
@Override
public Object[] toArray(Object[] a) {
return theList.toArray(a);
}
@Override
public void addListener(ListChangeListener<? super TreeItem<DataObject>> listChangeListener) {
changeListeners.add(listChangeListener);
}
@Override
public void removeListener(ListChangeListener<? super TreeItem<DataObject>> listChangeListener) {
changeListeners.remove(listChangeListener);
}
@Override
public boolean addAll(TreeItem<DataObject>... treeItems) {
return theList.addAll(treeItems);
}
@Override
public boolean setAll(TreeItem<DataObject>... treeItems) {
return theList.setAll(treeItems);
}
@Override
public boolean setAll(Collection<? extends TreeItem<DataObject>> treeItems) {
return theList.setAll(treeItems);
}
@Override
public boolean removeAll(TreeItem<DataObject>... treeItems) {
return theList.removeAll(treeItems);
}
@Override
public boolean retainAll(TreeItem<DataObject>... treeItems) {
return theList.retainAll(treeItems);
}
@Override
public void remove(int i, int i2) {
theList.remove(i, i2);
}
@Override
public Object[] toArray() {
return theList.toArray();
}
@Override
public boolean add(TreeItem<DataObject> dataObjectTreeItem) {
return theList.add(dataObjectTreeItem);
}
@Override
public boolean containsAll(Collection<?> c) {
return theList.containsAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
return theList.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return theList.retainAll(c);
}
@Override
public TreeItem<DataObject> set(int index, TreeItem<DataObject> element) {
return theList.set(index, element);
}
@Override
public void add(int index, TreeItem<DataObject> element) {
theList.add(index, element);
}
@Override
public TreeItem<DataObject> remove(int index) {
return theList.remove(index);
}
@Override
public void addListener(InvalidationListener invalidationListener) {
invalidationListeners.add(invalidationListener);
}
@Override
public void removeListener(InvalidationListener invalidationListener) {
invalidationListeners.remove(invalidationListener);
}
private void fireValueChangedEvent(ListChangeListener.Change<? extends TreeItem<DataObject>> change) {
for (ListChangeListener<? super TreeItem<DataObject>> listener : changeListeners) {
listener.onChanged(change);
}
}
@Override
public void handleEvent(Event event) {
// Here I add or remove TreeItem<DataObject> instances to the list based on event.
//
// At this point, onChanged() gets called above in my listener, but my changeListeners list is empty. There is
// no one to pass the Change on to.
}
}
感谢您的帮助。
在查看了 JavaFX 源代码后,我明白了这里发生了什么。
原来children的ObservableList的监听都是在TreeItem本身设置的,而不是像我想的那样是TreeView。这意味着任何覆盖 getChildren() 的 TreeView 子类必须 调用 super.getChildren() 并将其 children 添加到结果列表中。这意味着使用自定义 ObservableList 实现是不可能的,因为 TreeItem 被硬编码为使用 FXCollections.observableArrayList() 来创建列表。
我现在采取不同的方法来调用 super.getChildren(),添加我的 children,然后实例化另一个 object,它包含对该列表的引用,并且执行我应用程序的所有事件处理业务,根据需要在列表上进行操作。所以我的 getChildren() 方法现在看起来像这样。
private MyEventHandler eventHandler;
private ObservableList<TreeItem<DataObject>> children;
@Override
public ObservableList<TreeItem<DataObject>> getChildren() {
if (needChildren) {
needChildren = false;
children = super.getChildren();
eventHandler = new MyEventHandler(children); // handles app events
}
return children;
}
我已经为 TreeItems 列表创建了自定义 ObservableList 实现。我的自定义实现可以从我的应用程序内部监听各种通知(使用 OSGi EventAdmin),并相应地更新自身。然后我希望它的消费者(一个 TreeView 小部件)随着列表的更改而更新。但是,我看不到如何通知消费者。
在 ObservableList 子类中,我正在实现 addListener(ListChangeListener),我希望在将对象添加到小部件时调用它。然而,它从未被调用过;我没有听众,因此没有明显的方式在列表更改时通知任何人。我一定是遗漏了什么。
这是我的 TreeItem 实现的一个片段,returns 我的 ObservableList 实例响应 getChildren 调用:
@Override
public ObservableList<TreeItem<DataObject>> getChildren() {
if (needChildren) {
needChildren = false;
children = new MyObservableList();
}
return children;
}
这是我的自定义 ObservableList 实现的简化版本,它简单地包装了一个 FXCollections.observableArrayList 并添加了一个 OSGi 事件处理程序。我收听内部列表中的更改,以便我可以将这些更改传递给我的听众。
public class MyObservableList implements ObservableList<TreeItem<DataObject>>, EventHandler {
private List<ListChangeListener<? super TreeItem<DataObject>>> changeListeners = new ArrayList<>();
private List<InvalidationListener> invalidationListeners = new ArrayList<>();
private ObservableList<TreeItem<DataObject>> theList;
private int size;
public MyObservableList() {
theList = FXCollections.observableArrayList();
theList.addListener(new ListChangeListener<TreeItem<DataObject>>() {
@Override
public void onChanged(Change<? extends TreeItem<DataObject>> change) {
fireValueChangedEvent(change);
}
});
}
@Override
public int size() {
return theList.size();
}
@Override
public boolean isEmpty() {
return (size == 0);
}
@Override
public boolean contains(Object o) {
return theList.contains(o);
}
@Override
public Iterator iterator() {
return theList.iterator();
}
@Override
public boolean remove(Object o) {
return theList.remove(o);
}
@Override
public boolean addAll(Collection c) {
return theList.addAll(c);
}
@Override
public boolean addAll(int index, Collection c) {
return theList.addAll(index, c);
}
@Override
public void clear() {
theList.clear();
}
@Override
public TreeItem<DataObject> get(int index) {
return theList.get(index);
}
@Override
public int indexOf(Object o) {
return theList.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return theList.lastIndexOf(o);
}
@Override
public ListIterator listIterator() {
return theList.listIterator();
}
@Override
public ListIterator listIterator(int index) {
return theList.listIterator(index);
}
@Override
public List<TreeItem<DataObject>> subList(int fromIndex, int toIndex) {
return theList.subList(fromIndex, toIndex);
}
@Override
public Object[] toArray(Object[] a) {
return theList.toArray(a);
}
@Override
public void addListener(ListChangeListener<? super TreeItem<DataObject>> listChangeListener) {
changeListeners.add(listChangeListener);
}
@Override
public void removeListener(ListChangeListener<? super TreeItem<DataObject>> listChangeListener) {
changeListeners.remove(listChangeListener);
}
@Override
public boolean addAll(TreeItem<DataObject>... treeItems) {
return theList.addAll(treeItems);
}
@Override
public boolean setAll(TreeItem<DataObject>... treeItems) {
return theList.setAll(treeItems);
}
@Override
public boolean setAll(Collection<? extends TreeItem<DataObject>> treeItems) {
return theList.setAll(treeItems);
}
@Override
public boolean removeAll(TreeItem<DataObject>... treeItems) {
return theList.removeAll(treeItems);
}
@Override
public boolean retainAll(TreeItem<DataObject>... treeItems) {
return theList.retainAll(treeItems);
}
@Override
public void remove(int i, int i2) {
theList.remove(i, i2);
}
@Override
public Object[] toArray() {
return theList.toArray();
}
@Override
public boolean add(TreeItem<DataObject> dataObjectTreeItem) {
return theList.add(dataObjectTreeItem);
}
@Override
public boolean containsAll(Collection<?> c) {
return theList.containsAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
return theList.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return theList.retainAll(c);
}
@Override
public TreeItem<DataObject> set(int index, TreeItem<DataObject> element) {
return theList.set(index, element);
}
@Override
public void add(int index, TreeItem<DataObject> element) {
theList.add(index, element);
}
@Override
public TreeItem<DataObject> remove(int index) {
return theList.remove(index);
}
@Override
public void addListener(InvalidationListener invalidationListener) {
invalidationListeners.add(invalidationListener);
}
@Override
public void removeListener(InvalidationListener invalidationListener) {
invalidationListeners.remove(invalidationListener);
}
private void fireValueChangedEvent(ListChangeListener.Change<? extends TreeItem<DataObject>> change) {
for (ListChangeListener<? super TreeItem<DataObject>> listener : changeListeners) {
listener.onChanged(change);
}
}
@Override
public void handleEvent(Event event) {
// Here I add or remove TreeItem<DataObject> instances to the list based on event.
//
// At this point, onChanged() gets called above in my listener, but my changeListeners list is empty. There is
// no one to pass the Change on to.
}
}
感谢您的帮助。
在查看了 JavaFX 源代码后,我明白了这里发生了什么。
原来children的ObservableList的监听都是在TreeItem本身设置的,而不是像我想的那样是TreeView。这意味着任何覆盖 getChildren() 的 TreeView 子类必须 调用 super.getChildren() 并将其 children 添加到结果列表中。这意味着使用自定义 ObservableList 实现是不可能的,因为 TreeItem 被硬编码为使用 FXCollections.observableArrayList() 来创建列表。
我现在采取不同的方法来调用 super.getChildren(),添加我的 children,然后实例化另一个 object,它包含对该列表的引用,并且执行我应用程序的所有事件处理业务,根据需要在列表上进行操作。所以我的 getChildren() 方法现在看起来像这样。
private MyEventHandler eventHandler;
private ObservableList<TreeItem<DataObject>> children;
@Override
public ObservableList<TreeItem<DataObject>> getChildren() {
if (needChildren) {
needChildren = false;
children = super.getChildren();
eventHandler = new MyEventHandler(children); // handles app events
}
return children;
}