你的问题有几个方面(我不完全确定哪个方面是问题:-)我假设你的POJO以某种方式通知听众有关更改,可能是通过成为一个成熟的JavaBean。也就是说,它通过根据需要或通过其他方式触发 propertyChange 事件来遵守其通知协定 - 否则,无论如何,您都需要手动推送更改。
使 FX-ObservableList 在包含的元素发生突变时通知其自己的侦听器的基本方法是使用提供可观察量数组的自定义回调对其进行配置。如果元素具有 fx 属性,则可以执行如下操作:
Callback<Person, Observable[]> extractor = new Callback<Person, Observable[]>() {
@Override
public Observable[] call(Person p) {
return new Observable[] {p.lastNameProperty(), p.firstNameProperty()};
}
};
ObservableList<Person> teamMembers = FXCollections.observableArrayList(extractor);
// fill list
如果 pojo 是一个成熟的核心 javaBean,那么它的属性必须通过使用 JavaBeanProperty 来适应 fx 属性,f.i. :
Callback<PersonBean, Observable[]> extractor = new Callback<PersonBean, Observable[]>() {
List<Property> properties = new ArrayList<Property>();
@Override
public Observable[] call(PersonBean arg0) {
JavaBeanObjectProperty lastName = null;
JavaBeanObjectProperty age = null;
try {
lastName = JavaBeanObjectPropertyBuilder.create()
.bean(arg0).name("lastName").build();
age = JavaBeanObjectPropertyBuilder.create()
.bean(arg0).name("age").build();
// hack around losing weak references ...
properties.add(age);
properties.add(lastName);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return new Observable[] {lastName, age};
}
};
ObservableList<Person> teamMembers = FXCollections.observableArrayList(extractor);
// fill list
请注意一个警告:如果不在某个地方对适应的属性进行强烈引用,它们将很快被垃圾收集 - 然后似乎根本没有效果(一次又一次地落入陷阱,不确定是否有一个好的策略来避免它)。
对于任何其他(可能是粗粒度的)通知方法,您可以实现自定义适配器:下面的适配器侦听 Bean 的所有属性更改。侦听其他类型的事件将非常相似。
/**
* Adapt a Pojo to an Observable.
* Note: extending ObservableValue is too much, but there is no ObservableBase ...
*
* @author Jeanette Winzenburg, Berlin
*/
public class PojoAdapter<T> extends ObservableValueBase<T> {
private T bean;
private PropertyChangeListener pojoListener;
public PojoAdapter(T pojo) {
this.bean = pojo;
installPojoListener(pojo);
}
/**
* Reflectively install a propertyChangeListener for the pojo, if available.
* Silently does nothing if it cant.
* @param item
*/
private void installPojoListener(T item) {
try {
Method method = item.getClass().getMethod("addPropertyChangeListener",
PropertyChangeListener.class);
method.invoke(item, getPojoListener());
} catch (NoSuchMethodException | SecurityException | IllegalAccessException |
IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* Returns the propertyChangeListener to install on each item.
* Implemented to call notifyList.
*
* @return
*/
private PropertyChangeListener getPojoListener() {
if (pojoListener == null) {
pojoListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
fireValueChangedEvent();
}
};
}
return pojoListener;
}
@Override
public T getValue() {
return bean;
}
}
它的用法与上面相同(变得无聊,不是吗:-)
Callback<PersonBean, Observable[]> extractor = new Callback<PersonBean, Observable[]>() {
@Override
public Observable[] call(PersonBean arg0) {
return new Observable[] {new PojoAdapter<PersonBean>(arg0)};
}
};
ObservableList<Person> teamMembers = FXCollections.observableArrayList(extractor);
// fill list
不幸的是,使用如此酷的列表自动更新ListView将无法可靠地工作,因为仅在jdk8中修复了一个错误。在早期版本中,您又回到了正方形 1 - 以某种方式侦听更改,然后手动更新列表:
protected void notifyList(Object changedItem) {
int index = list.indexOf(changedItem);
if (index >= 0) {
// hack around RT-28397
//https://javafx-jira.kenai.com/browse/RT-28397
list.set(index, null);
// good enough since jdk7u40 and jdk8
list.set(index, changedItem);
}
}