我构建了一个自定义属性并将其添加到可观察列表中。但是如果属性内容发生更改,则不会调用侦听器。以下代码段显示了' building':
public static final class TestObject {
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper();
private final BooleanProperty selected = new SimpleBooleanProperty(false);
public TestObject(String title) {
this.title.set(title);
}
public String getTitle() {
return title.get();
}
public ReadOnlyStringProperty titleProperty() {
return title.getReadOnlyProperty();
}
public boolean getSelected() {
return selected.get();
}
public BooleanProperty selectedProperty() {
return selected;
}
public void setSelected(boolean selected) {
this.selected.set(selected);
}
@Override
public int hashCode() {
return Objects.hash(title.get());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final TestObject other = (TestObject) obj;
return Objects.equals(this.title.get(), other.title.get());
}
@Override
public String toString() {
return "TestObject{" +
"title=" + title.get() +
", selected=" + selected.get() +
'}';
}
}
这是我的POJO类,其内部属性值如name和selected。
public static final class TestProperty extends SimpleObjectProperty<TestObject> {
public TestProperty(String name) {
super(new TestObject(name));
init();
}
public TestProperty(TestObject testObject) {
super(testObject);
init();
}
public String getTitle() {
return getValue().getTitle();
}
public void setSelected(boolean selected) {
getValue().setSelected(selected);
}
public boolean getSelected() {
return getValue().getSelected();
}
public BooleanProperty selectedProperty() {
return getValue().selectedProperty();
}
public ReadOnlyStringProperty titleProperty() {
return getValue().titleProperty();
}
@Override
public void set(TestObject testObject) {
super.set(testObject);
init();
}
@Override
public void setValue(TestObject testObject) {
super.setValue(testObject);
init();
}
private void init() {
if (get() == null)
return;
get().titleProperty().addListener((v, o, n) -> fireValueChangedEvent());
get().selectedProperty().addListener((v, o, n) -> {
fireValueChangedEvent();
});
}
}
这是我基于POJO的自定义属性。所有属性更改都将触发我的自定义属性的更改事件。
@Test
public void testSimple() {
final AtomicInteger counter = new AtomicInteger(0);
final TestProperty testProperty = new TestProperty("Test");
testProperty.addListener(observable -> {
System.out.println("New state: " + testProperty.get().toString());
counter.incrementAndGet();
});
testProperty.setSelected(true);
testProperty.setSelected(false);
Assert.assertEquals(2, counter.intValue());
}
在此测试中,您可以看到属性更改事件正常工作。
@Test
public void testList() {
final AtomicInteger counter = new AtomicInteger(0);
final ObservableList<TestProperty> observableList = new ObservableListWrapper<>(new ArrayList<>());
observableList.add(new TestProperty("Test 1"));
observableList.add(new TestProperty("Test 2"));
observableList.add(new TestProperty("Test 3"));
observableList.addListener(new ListChangeListener<TestProperty>() {
@Override
public void onChanged(Change<? extends TestProperty> change) {
System.out.println("**************");
}
});
observableList.addListener((Observable observable) -> {
System.out.println("New state: " + ((TestProperty) observable).get().toString());
counter.incrementAndGet();
});
observableList.get(1).setSelected(true);
observableList.get(2).setSelected(true);
observableList.get(1).setSelected(false);
observableList.get(2).setSelected(false);
Assert.assertEquals(4, counter.intValue());
}
但在此代码中,您会看到,如果列表中的属性值已更改,则可观察列表不会调用失效侦听器,也不会调用更改侦听器。
有什么问题?
感谢。
答案 0 :(得分:18)
创建一个可观察的列表,该列表将发送&#34; list更新&#34;通知如果列表元素的属性发生更改,则需要使用extractor创建列表。 extractor
是Callback
,它将列表的每个元素映射到Observable
s的数组。如果Observable
的任何更改,将通知列表中注册的InvalidationListener
和ListChangeListener
。
因此,在您的testList()
方法中,您可以
final ObservableList<TestProperty> observableList = FXCollections.observableList(
new ArrayList<>(),
(TestProperty tp) -> new Observable[]{tp.selectedProperty()});
如果标题能够更改,并且您还希望列表在发生这种情况时收到通知,那么您也可以这样做:
final ObservableList<TestProperty> observableList = FXCollections.observableList(
new ArrayList<>(),
(TestProperty tp) -> new Observable[]{tp.selectedProperty(), tp.titleProperty()});
请注意,因为提取器是Callback
(本质上是函数),所以实现可以是任意复杂的(根据另一个属性的条件有条件地观察一个属性等)。
答案 1 :(得分:0)
只要列表中包含的属性被修改,ObservableList就不会通知监听器,它会在通知列表时通知。
修改测试时可以看到:
@Test
public void testList() {
final AtomicInteger counter = new AtomicInteger(0);
final ObservableList<TestProperty> observableList = new ObservableListWrapper<>(new ArrayList<>());
observableList.addListener(new ListChangeListener<TestProperty>() {
@Override
public void onChanged(Change<? extends TestProperty> change) {
System.out.println("**************");
counter.incrementAndGet();
}
});
observableList.add(new TestProperty("Test 1"));
observableList.add(new TestProperty("Test 2"));
observableList.add(new TestProperty("Test 3"));
observableList.get(1).setSelected(true);
observableList.get(2).setSelected(true);
observableList.get(1).setSelected(false);
observableList.get(2).setSelected(false);
Assert.assertEquals(3, counter.intValue());
}
编辑:添加了一个示例ObserverListener装饰器,它根据OP的需要提供ObservableValue更改侦听器的自动注册/注销。
/**
* Decorates an {@link ObservableList} and auto-registers the provided
* listener to all new observers, and auto-unregisters listeners when the
* item is removed from the list.
*
* @param <T>
*/
public class ObservableValueList<T extends ObservableValue> implements ObservableList<T> {
private final ObservableList<T> list;
private final ChangeListener<T> valueListener;
public ObservableValueList(ObservableList<T> list, ChangeListener<T> valueListener) {
this.list = list;
//list to existing contents of list
this.list.stream().forEach((item) -> item.addListener(valueListener));
//register listener which will add/remove listner on change to list
this.list.addListener((Change<? extends T> change) -> {
change.getAddedSubList().stream().forEach(
(item) -> item.addListener(valueListener));
change.getRemoved().stream().forEach(
(item) -> item.removeListener(valueListener));
});
this.valueListener = valueListener;
}
/* What follows is all the required delegate methods */
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Iterator<T> iterator() {
return list.iterator();
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public <T> T[] toArray(T[] ts) {
return list.toArray(ts);
}
@Override
public boolean add(T e) {
return list.add(e);
}
@Override
public boolean remove(Object o) {
return list.remove(o);
}
@Override
public boolean containsAll(Collection<?> clctn) {
return list.containsAll(clctn);
}
@Override
public boolean addAll(Collection<? extends T> clctn) {
return list.addAll(clctn);
}
@Override
public boolean addAll(int i, Collection<? extends T> clctn) {
return list.addAll(i, clctn);
}
@Override
public boolean removeAll(Collection<?> clctn) {
return list.removeAll(clctn);
}
@Override
public boolean retainAll(Collection<?> clctn) {
return list.retainAll(clctn);
}
@Override
public void replaceAll(UnaryOperator<T> uo) {
list.replaceAll(uo);
}
@Override
public void sort(Comparator<? super T> cmprtr) {
list.sort(cmprtr);
}
@Override
public void clear() {
list.clear();
}
@Override
public T get(int i) {
return list.get(i);
}
@Override
public T set(int i, T e) {
return list.set(i, e);
}
@Override
public void add(int i, T e) {
list.add(i, e);
}
@Override
public T remove(int i) {
return list.remove(i);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public ListIterator<T> listIterator() {
return list.listIterator();
}
@Override
public ListIterator<T> listIterator(int i) {
return list.listIterator(i);
}
@Override
public List<T> subList(int i, int i1) {
return list.subList(i, i1);
}
@Override
public Spliterator<T> spliterator() {
return list.spliterator();
}
@Override
public void addListener(ListChangeListener<? super T> ll) {
list.addListener(ll);
}
@Override
public void removeListener(ListChangeListener<? super T> ll) {
list.removeListener(ll);
}
@Override
public boolean addAll(T... es) {
return list.addAll(es);
}
@Override
public boolean setAll(T... es) {
return list.setAll(es);
}
@Override
public boolean setAll(Collection<? extends T> clctn) {
return list.setAll(clctn);
}
@Override
public boolean removeAll(T... es) {
return list.removeAll(es);
}
@Override
public boolean retainAll(T... es) {
return list.retainAll(es);
}
@Override
public void remove(int i, int i1) {
list.remove(i, i1);
}
@Override
public FilteredList<T> filtered(Predicate<T> prdct) {
return list.filtered(prdct);
}
@Override
public SortedList<T> sorted(Comparator<T> cmprtr) {
return list.sorted(cmprtr);
}
@Override
public SortedList<T> sorted() {
return list.sorted();
}
@Override
public void addListener(InvalidationListener il) {
list.addListener(il);
}
@Override
public void removeListener(InvalidationListener il) {
list.removeListener(il);
}
}
答案 2 :(得分:0)
以下代码显示了具有可观察值的可观察列表的简单实现:
public class ObservableValueListWrapper<E extends ObservableValue<E>> extends ObservableListWrapper<E> {
public ObservableValueListWrapper(List<E> list) {
super(list, o -> new Observable[] {o});}}
或者您必须使用POJO创建列表:
final ObservableList<MyPOJO> list = new ObservableListWrapper<>(new ArrayList(), o -> new Observable[] { new MyPOJOProperty(o) });
或者您使用它:
final ObservableList<MyPOJO> list = new ObservableListWrapper<>(new ArrayList(), o -> { return new Observable[] {
o.value1Property(),
o.value2Property(),
...};});
就是这样!感谢。