奇怪的TableView.itemsProperty行为?

时间:2013-10-04 07:08:51

标签: java javafx-2 javafx javafx-8

假设我将一个ChangeListener添加到TableView的itemsProperty中。何时会调用ChangeListener的更改方法?

我尝试添加TableView项目指向的空List。结果 - ChangeListener的已更改方法未被调用。

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);

但是,我也尝试添加一个空List,然后让TableView的项指向它。结果 - 调用ChangeListener的已更改方法。

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本身的类型相匹配。”

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

2 个答案:

答案 0 :(得分: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!

如果您的代码想要监听内容的更改,那就太讨厌了 - 每当项目值的标识发生变化时,它都需要重新连接ListChangeListener,但是不能使用changeListener,因为它基于相等性而触发。顺便说一句,甚至fx内部代码也出错了hot-fixed by a dirty hack

没有好的解决方案,只有一个couple of suboptimal options

  • 使用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;
}

答案 1 :(得分:0)

TableView没有实现添加view documentation

的方法

我的方法如下:

初始化TableView itemList:

tableX.setItems(itemListX);

您也可以使用TableView的默认列表初始化它:

tableX.getItems.addAll(itemListX);

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

动态添加项目的方法:

1 - 如果您仍然引用itemListX:

itemListX.add(item);

这将更新TableView,因为该表会观察ObservableList itemListX。

2-Else,如果你不再:

tableX.getItems().add(item);