Problem
When items are removed from an ObservableList
, a change event is fired where getFrom()
gives the location of the removal and getRemoved()
gives a list of items that were removed. The documentation says:
The
getRemoved()
method returns a list of elements that have been replaced or removed from the list.
It is not stated as such, but I took it to be implied that the list of items is a contiguous sub-list from the original list. I've written a lot of code with that assumption, but am now encountering difficulties with TreeTableView
's selection model, which doesn't behave that way.
Example
Take for instance a simple tree table with three "Node" rows. If I select those three rows...
...and then click and select just the middle row...
...the change event fired on treeTableView.getSelectionModel().getSelectedItems()
looks like this:
{ [TreeItem [ value: Node 1 ], TreeItem [ value: Node 3 ]] removed at 0, }
In a single change event it reports that "Node 1" and "Node 3" were removed from index 0 of the selectedItems
list.
I would have expected the Change
object to have two separate removal events separated by next()
calls. The first call to next()
would tell me that "Node 1" was removed at index 0, and the second call to next()
would tell me that "Node 3" was removed at index 1. But no, I get a single event with both rows listed at once.
Question
Can getRemoved()
really return non-contiguous items? Is this a misunderstanding on my part of how list change events work, or is it a bug in TreeTableView
?
Normally I'm hesitant to blame standard libraries, but this wouldn't be the first bug I've found in JavaFX, so it's not unthinkable.
Update
If I add a call to setShowRoot(false)
, the behavior changes. I get what I would expect, the removal split into two pieces:
{ [TreeItem [ value: Node 1 ]] removed at 0, [TreeItem [ value: Node 3 ]] removed at 1, }
Also, here is my MCVE:
import java.util.*;
import javafx.application.*;
import javafx.beans.property.*;
import javafx.collections.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.stage.*;
public class TreeTableSelectionEvents extends Application {
public void start(Stage stage) {
// Root node.
TreeItem<String> root = new TreeItem<>("Root");
root.setExpanded(true);
root.getChildren().setAll(Arrays.asList(
new TreeItem<>("Node 1"),
new TreeItem<>("Node 2"),
new TreeItem<>("Node 3")
));
// Single column.
TreeTableColumn<String, String> column = new TreeTableColumn<>("Column");
column.setPrefWidth(150);
column.setCellValueFactory((TreeTableColumn.CellDataFeatures<String, String> p) -> {
return new ReadOnlyStringWrapper(p.getValue().getValue());
});
// Tree table.
TreeTableView<String> table = new TreeTableView<>(root);
table.getColumns().add(column);
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
// table.setShowRoot(false);
table.getSelectionModel().getSelectedItems().addListener(
(ListChangeListener.Change<? extends TreeItem<String>> change) -> {
System.out.printf("item change = %s, list is now %s%n", change, change.getList());
}
);
table.getSelectionModel().getSelectedIndices().addListener(
(ListChangeListener.Change<? extends Integer> change) -> {
System.out.printf("index change = %s, list is now %s%n", change, change.getList());
}
);
// Stage.
stage.setScene(new Scene(table));
stage.show();
}
}
getTo()
return in that scenario? – LeathermangetTo()
=getFrom()
=0
. – ThurmangetRemoved()
can return non-contiguous items". Is there any reason to believe that's a bug? I don't see anywhere in the documentation that states that's not allowed. – LeathermangetRemoved()
aren't contiguous then I can't unambiguously determine which items were removed. It could be any of the duplicates. I suspect but am not sure that this is a flaw in the documentation and a bug inTreeTableViewSelectionModel
. – Thurman