Reputation: 5960
Let's say I'll add a ChangeListener to a TableView's itemsProperty. When would the ChangeListener's changed method be called?
I tried adding to the empty List where the TableView's items points. The result - The ChangeListener's changed method didn't get called.
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);
However, I also tried adding to an empty List and then let TableView's items point on it. The result - The ChangeListener's changed method got called.
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);
I looked it up on http://docs.oracle.com/javafx/2/api/javafx/scene/control/TableView.html#itemsProperty() but it only says "The underlying data model for the TableView. Note that it has a generic type that must match the type of the TableView itself."
I'm asking this because I might miss out on some other important circumstances.
Upvotes: 3
Views: 855
Reputation: 51535
A not fully documented fact (aka: implementation detail) is that ObjectProperty only fires on
!oldValue.equals(newValue); // modulo null checking
That's critical for a list-valued object property, as lists are specified to be equal if all their elements are equal. In particular, all empty lists are equal to each other, thus replacing one empty list by another empty list as in your first snippet will not make the property fire:
// 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!
That's nasty if your code wants to listen to changes of the content - it would need to re-wire the ListChangeListeners whenever the identity of the items value changes but can't with a changeListener because that fires based on equality. BTW, even fx-internal code got that wrong and hot-fixed by a dirty hack
And no nice solution available, just a couple of suboptimal options
A code snippet I use:
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;
}
Upvotes: 4
Reputation: 866
TableView does not have implemented the method add view documentation
My aproach is the following:
To initialize the TableView itemList:
tableX.setItems(itemListX);
you could also initialize it by using the default list of the TableView:
tableX.getItems.addAll(itemListX);
in this case it will copy the list.
And the aproach to add items dynamically:
1-If you still have a reference to itemListX:
itemListX.add(item);
this you will update the TableView since the table observes the ObservableList itemListX.
2-Else, if you dont any more:
tableX.getItems().add(item);
Upvotes: 0