It is hard to explain so I'll use an example:
@Override
public void start(Stage primaryStage) throws Exception
{
final VBox vbox = new VBox();
final Scene sc = new Scene(vbox);
primaryStage.setScene(sc);
final TableView<Person> table = new TableView<>();
final TableColumn<Person, String> columnName = new TableColumn<Person, String>("Name");
table.getColumns().add(columnName);
final ObservableList<Person> list = FXCollections.observableArrayList();
list.add(new Person("Hello"));
list.add(new Person("World"));
Bindings.bindContent(table.getItems(), list);
columnName.setCellValueFactory(new PropertyValueFactory<>("name"));
vbox.getChildren().add(table);
final Button button = new Button("test");
button.setOnAction(event ->
{
final Person removed = list.remove(0);
removed.setName("Bye");
list.add(0, removed);
});
vbox.getChildren().add(button);
primaryStage.show();
}
public static class Person
{
private String name = "";
public Person(String n)
{
name = n;
}
public String getName()
{
return name;
}
public void setName(String n)
{
name = n;
}
}
In this example, I show a TableView
with a single column named "Name". Running this sample code, you will get two rows: first row with "Hello" in "Name" column; and second row with "World" in "Name" column.
Additionally, there is a button, this button removes the first Person
object from the list, then makes some changes to the object, then adds it back in at the same index. Doing so would cause any ListChangeListener
added to the ObservableList
to be triggered, and I have tested this to be true.
I would expect the row with "Hello" to be replaced with "Bye", but it seems like the TableView
continues to show "Hello". If I used a TimeLine
to add delay before I add the removed Person
object back to the list, it would change to "Bye".
final Timeline tl = new Timeline(new KeyFrame(Duration.millis(30), ae -> list.add(0, removed)));
tl.play();
Is there something weird with the API? Is there any way to do this without this problem?