当前位置: 首页 > 知识库问答 >
问题:

JavaFX:如果ObservableList的元素更改,则更新ListView

韩耘豪
2023-03-14

我想使用JavaFX ListView控件显示一个人员列表(在POJOS中编码,包含一个name和surname属性)。我创建了ListView,并将persons列表添加为ObservableList。如果我在ObservableList中删除或添加一个新人,那么一切都可以正常工作,但是POJO中的更改不会触发ListView的更新。我必须从ObservableList中移除和添加修改后的POJO来触发ListView的更新。在没有上述解决办法的情况下,是否有可能在POJO中显示更改?

共有1个答案

闽焕
2023-03-14

您的问题有几个方面(我不完全确定哪个方面是问题:-)我假设您的POJO以某种方式通知监听器有关更改,可能是通过成为一个成熟的JavaBean。也就是说,它通过根据需要激发propertyChange事件或通过其他方式遵守通知契约-否则,您将需要手动推送更改。

使FX-ObservableList在包含元素的突变时通知自己的侦听器的基本方法是使用一个提供可观测数组的自定义回调来配置FX-ObservableList。如果元素具有fx-properties,则可以执行以下操作:

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,那么它的属性必须适应fx-properties、f.i。通过使用JavaBeanProperty:

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的所有propertyChanges。听其他类型的事件也很相似。

/**
 * 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

不幸的是,由于一个只在JDK8中修复的bug,使用如此酷的列表自动更新ListView将无法可靠地工作。在早期版本中,您又回到了square 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);
    }
}
 类似资料:
  • 我有一个表视图,每次都很好地填充, 我的主控制器: 我的测试类: 扩展测试类并覆盖其运行的Test1类: 我的aHandler: 因为tbl1绑定到Handler。getInstance()。GetData(),第一次初始化该类时,我看到列Test填充了值1,因为TestData=1;但当计时器开始更改测试数据时,表视图不会获得新的赋值。我做错了什么? 我尽我所能解释这个问题,请让我知道,如果它仍

  • 问题内容: 是否可以在sql中执行更新语句,但仅在更新不同时才执行更新? 例如 如果在数据库中, 不应 执行任何类型的更新 但是,如果 这 应该 执行更新。 问题答案: 使用更新前触发器可以做到这一点。在此触发器中,您可以将旧值与新值进行比较,并在新值不变的情况下取消更新。但这将导致呼叫者网站上的错误。 我不知道为什么要这样做,但是这里有几种可能性: 性能:这里没有性能提升,因为更新不仅需要找到正

  • 我有一个拥有数千个条目的Java ObservableList,它支持JavaFX TableView,每秒接收数百个更新。 ObservableList由ArrayList支持。可以对列表应用任意排序顺序。更新可能会改变列表中单个实体的排序顺序。如果我试图在每次更新后预制排序,我会有性能问题,所以目前我有一个后台任务每秒钟执行一次排序。不过,如果可能的话,我想尝试实时排序。

  • 我的问题是,当更改时,我的(复选框列表视图)不会更新。 只有当我使用有日期的JavaFX版本和有日期的JRE(jre6和JFX2.2)时,才会出现这个问题。当我使用jre8和它所包含的JavaFX时,问题就没有了,列表也会很好地刷新。 上面描述的最新JavaFX上的工作源代码: 名单: 列表使用的类具有以下属性: 问题是,当我更改列表项时,ListView在旧的JavaFX版本上不会改变。 值得一

  • 我知道有人在不同的日期问过类似的问题,但我会在这里放一个SSCCE,尽量简单地问这个问题。 我希望能够更新数据模型,并使其上的任何视图自动更新,这样任何更新模型的调用者都不会知道当前有任何视图。这是我到目前为止学到/尝试的,并且没有调用它不会更新。我错过了什么? 主要的java: 全体船员Java语言

  • 问题内容: 我想动态更新元素的文本: 我是jQuery的新手,因此对我来说,这项任务似乎非常具有挑战性。有人可以指出我要使用的功能/选择器吗? 如果可能的话,我想在不为需要更改的文本添加新容器的情况下执行此操作。 问题答案: 在Javascript中,该属性为您提供元素的所有子节点,包括文本节点。 因此,如果您知道要更改的文本始终是元素中的第一件事,那么请给出以下HTML: 您可以这样做: 当然,