2

假设我将向 TableView 的 itemsProperty 添加一个 ChangeListener。什么时候调用 ChangeListener 的 changed 方法?

我尝试添加到 TableView 的项目指向的空列表中。结果 - ChangeListener 的 changed 方法没有被调用。

tableView.itemsProperty().addListener(new ChangeListener() {
    @Override
    public void changed(ObservableValue ov, Object t, Object t1) {
        System.out.println("Changed!");
    }
});

final ObservableList data = FXCollections.observableArrayList(new ArrayList());
data.clear();
//data.add(new Object()); don't call this yet
tableView.setItems(data);
data.clear();
data.add(new Object());
tableView.setItems(data);

但是,我也尝试添加到一个空列表,然后让 TableView 的项目指向它。结果 - ChangeListener 的 changed 方法被调用。

tableView.itemsProperty().addListener(new ChangeListener() {
    @Override
    public void changed(ObservableValue ov, Object t, Object t1) {
        System.out.println("Changed!");
    }
});

final ObservableList data = FXCollections.observableArrayList(new ArrayList());
data.clear();
data.add(new Object()); 
tableView.setItems(data);
data.clear();
data.add(new Object());
tableView.setItems(data);

我在http://docs.oracle.com/javafx/2/api/javafx/scene/control/TableView.html#itemsProperty()上查找了它,但它只说“TableView 的基础数据模型。注意它具有必须与 TableView 本身的类型匹配的泛型类型。”

我问这个是因为我可能会错过其他一些重要的情况。

4

2 回答 2

3

一个没有完全记录的事实(又名:实现细节)是 ObjectProperty 只触发

!oldValue.equals(newValue); // modulo null checking 

这对于列表值对象属性至关重要,因为如果列表的所有元素都相等,则列表被指定为相等。特别是,所有空列表都彼此相等,因此在您的第一个片段中将一个空列表替换为另一个空列表不会使属性触发:

 // items empty initially
 TableView table = new TableView()
 table.itemsProperty().addListener(....)
 ObservableList empty = FXCollections.observableArrayList();
 // replace initial empty list by new empty list
 table.setItems(empty);
 // no change event was fired!

如果您的代码想要监听内容的变化,那就太糟糕了——每当项目值的标识发生变化但不能使用 changeListener 时,它需要重新连接 ListChangeListeners,因为它是基于相等性触发的。顺便说一句,即使是 fx 内部代码也弄错了,并被肮脏的黑客热修复

没有好的解决方案,只有几个次优的选择

  • 使用 InvalidationListener 而不是 changeListener
  • 绑定(单向!)一个 ListProperty 到列表值对象属性并监听后者
  • 使用结合了上述内容的适配器,至少可以将其排除在外

我使用的代码片段:

public static <T> ListProperty<T> listProperty(final Property<ObservableList<T>> property) {
    Objects.requireNonNull(property, "property must not be null");
    ListProperty<T> adapter = new ListPropertyBase<T>() {
        // PENDING JW: need weakListener?
        private InvalidationListener hack15793;
        {
            Bindings.bindBidirectional(this, property);
            hack15793 = o -> {
                ObservableList<T> newItems =property.getValue();
                ObservableList<T> oldItems = get();
                // force rewiring to new list if equals
                boolean changedEquals = (newItems != null) && (oldItems != null) 
                        && newItems.equals(oldItems);
                if (changedEquals) {
                    set(newItems);
                }
            };
            property.addListener(hack15793);
        }

        @Override
        public Object getBean() {
            return null; // virtual property, no bean
        }

        @Override
        public String getName() {
            return property.getName();
        }

        @Override
        protected void finalize() throws Throwable {
            try {
                Bindings.unbindBidirectional(property, this);
                property.removeListener(hack15793);
            } finally {
                super.finalize();
            }
        }

    };
    return adapter;
}
于 2014-10-18T08:50:06.883 回答
0

TableView 没有实现方法添加视图文档

我的方法如下:

初始化 TableView itemList:

tableX.setItems(itemListX);

您还可以使用 TableView 的默认列表对其进行初始化:

tableX.getItems.addAll(itemListX);

在这种情况下,它将复制列表。

以及动态添加项目的方法:

1-如果您仍然有对 itemListX 的引用:

itemListX.add(item);

由于表观察到ObservableList itemListX,因此您将更新 TableView。

2-否则,如果你不再:

tableX.getItems().add(item);
于 2013-10-04T11:33:25.850 回答