Reputation: 169
Using JavaFX (v15) I want a TableView that sorts by the entire row/object in the table if no columns are selected and by columns if a column header is clicked. If the columns are unclicked then it should return to displaying a sort of the rows by the objects natural order or a specified comparator.
So something like:
@FXML TableView<Person> tableview;
ObserverableList<Person> list = FXCollections.observableArrayList<>();
SortedList<Person> sorted = new SortedList<>(list);
sorted.comparatorProperty().bind(tableview.comparatorProperty());
tableview.setItems(sorted);
It does NOT appear sorted. It just gets whatever order the items iterate in the wrapped Observable List. Is this because SortedList constructed without a comparator is actually an unsorted list?? (Which is the dumbest design I've ever seen). It will sort by columns. Why doesn't the TableView when given a SortedList actually sort when columns aren't clicked?
If I change to:
@FXML TableView<Person> tableview;
ObserverableList<Person> list = FXCollections.observableArrayList<>();
SortedList<Person> sorted = new SortedList<>(list, (a,b) -> a.compareTo(b));
tableview.setItems(sorted);
Then the TableView will appear sorted... however, clicking on a column yields:
Feb 05, 2021 4:38:52 PM javafx.scene.control.TableView$3 call INFO: TableView items list is a SortedList, but the SortedList comparator should be bound to the TableView comparator for sorting to be enabled (e.g. sortedList.comparatorProperty().bind(tableView.comparatorProperty());).
If I put back the property binding between the SortedList and the TableView then of course my comparator is ignored.
How does one implement a table view that without columns selected for sort the rows will appear sorted by natural comparable order or by comparator and yet will sort by individual columns when those are selected.
Upvotes: 2
Views: 845
Reputation: 51524
After playing a bit, it turned out that my initial comment
there's no direct simple (never investigated sortPolicy nor reacting to sortEvents :) support
was misleading (to put it mildly) - the not yet investigated sortPolicy looks like the way to go.
The basic idea is a custom sort policy that
A utility method (beware: not formally tested!)
public static <T> Callback<TableView<T>, Boolean> emptySortOrderPolicy(Comparator<? super T> comparator) {
return cc -> {
if (cc.getItems() instanceof SortedList) {
SortedList<T> sortedItems = (SortedList<T>) cc.getItems();
if (cc.getSortOrder().isEmpty()) {
sortedItems.comparatorProperty().unbind();
sortedItems.comparatorProperty().set(comparator);
return true;
} else {
sortedItems.comparatorProperty().bind(cc.comparatorProperty());
}
}
return TableView.DEFAULT_SORT_POLICY.call(cc);
};
}
Usage:
SortedList<ComparableItem> sorted = new SortedList<>(ComparableItem.items());
TableView<ComparableItem> table = new TableView<>(sorted);
table.setSortPolicy(emptySortOrderPolicy(Comparator.naturalOrder()));
Upvotes: 1