2

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.

3
  • 3
    Does Person implement Comparable<Person>? Commented Feb 6, 2021 at 0:55
  • don't quite understand what you mean by without columns selected - but even though: there's no direct simple (never investigated sortPolicy nor reacting to sortEvents :) support: you either let the default sorting (which basically combines the comparators from the columns that are in the sortOrder) do its job or have to do all the heavy lifting (like f.i. keeping selection state) yourself. To tricks the first into using a per-item comparator, you can use a hidden column carrying the item and set the sortOrder to include only that hidden column as appropriate. Commented Feb 6, 2021 at 11:39
  • I also found the setSortPolicy option. But this still begs the question... Why are there so many "examples" using SortedList. SortedList is actually unsorted without being constructed with a comparator argument and if you do construct it with a comparator argument to get sorting then it isn't bound to the TableView's comparator... which eliminates the ability to sort by columns. Silly. Commented Feb 7, 2021 at 17:45

1 Answer 1

1

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

  • checks if the items is-a SortedList
  • if so and the sortOrder is not empty, bind its comparator to the table's comparator and delegate to the default policy
  • if not, set a custom comparator (f.i. naturalOrder) and return

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()));
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.