betaman
betaman

Reputation: 1895

Javafx: Re-sorting a column in a TableView

I have a TableView associated to a TreeView. Each time a node in the TreeView is selected, the TableView is refreshed with different data.

I am able to sort any column in the TableView, just pressing the corresponding column header. That works fine.

But: when I select a different node in the tree-view, eventhough the column headers keep showing as sorted. The data is not.

Is there a way to programmatically enforce the sort order made by the user each time the data changes?

Upvotes: 15

Views: 29127

Answers (8)

Mohd ar
Mohd ar

Reputation: 41

You can also do this for 0 or more Sort-Columns:

List<TableColumn<Room, ?>> sortColumns = new LinkedList<>(rooms.getSortOrder());
// rooms.setItems(...)
rooms.getSortOrder().addAll(sortColumns);

The reason why you create a new LinkedList is that you don't wanna just point at rooms.getSortOrder() like this:

List<TableColumn<Room, ?>> sortColumns = rooms.getSortOrder();

because this way both rooms.getSortOrder() and sortColumns will become empty after you call rooms.setItems(...) which seems to clear the rooms.getSortOrder().

Upvotes: 0

kerner1000
kerner1000

Reputation: 3558

You can also use a SortedList.

SortedList<MatchTableBean> tableItems = new SortedList<>(
        observableList, Comparator.comparing(MatchTableBean::isMarker).reversed().thenComparing(MatchTableBean::getQueryRT));
    tableItems.comparatorProperty().bind(table.comparatorProperty());
    table.setItems(tableItems);

This way the table is sorted, even when the content changes or is completely replaced.

Upvotes: 0

DaveB
DaveB

Reputation: 2163

If you use the TableView.setItems() method, it appears to reset several aspects of the TableView. Leave the ObservableList in the TableView in place, clear its contents, and then add your new items. Then, TableView.sort() will still know which columns were previously sorted and it will work. Like this:

  tableView.getItems().clear();
  tableView.getItems().addAll(newTableData);
  tableView.sort();

Upvotes: 6

maddin79
maddin79

Reputation: 171

I had the same problem and found out that after an update of the data you only have to call the function sort() on the table view:

TableView rooms;
...
// Update data of rooms
...
rooms.sort()

The table view knows the columns for sorting thus the sort function will sort the new data in the wanted order. This function is only available in Java 8.

Upvotes: 17

Brian Blonski
Brian Blonski

Reputation: 1802

Marco Jakob's answer is good for most cases, but I found that I needed to create a comparator that matches the table sort order for more flexibility. You can then use any method that takes a comparator to do sorting, searching, etc. To create the comparator, I extended that ComparatorChain class from apache's Common-Collections to easily do multiple column sorting. It looks like this.

public class TableColumnListComparator extends ComparatorChain {
    public TableColumnListComparator(ObservableList<? extends TableColumn> columns) {
        // Get list of comparators from column list.
        for (TableColumn column : columns) {
            addComparator(new ColumnComparator(column));
        }
    }

    /**
     * Compares two items in a table column as if they were being sorted in the TableView.
     */
    private static class ColumnComparator implements Comparator {

        private final TableColumn column;

        /**
         * Default Constructor.  Creates comparator based off given table column sort order.
         *
         * @param column
         */
        public ColumnComparator(TableColumn column) {
            this.column = column;
        }

        @Override
        public int compare(Object o1, Object o2) {
            // Could not find a way to do this without casts unfortunately
            // Get the value of the column using the column's cell value factory.
            final ObservableValue<?> obj1 = (ObservableValue) column.getCellValueFactory().call(
                    new TableColumn.CellDataFeatures(column.getTableView(), column, o1));
            final ObservableValue<?> obj2 = (ObservableValue) column.getCellValueFactory().call(
                    new TableColumn.CellDataFeatures(column.getTableView(), column, o2));
            // Compare the column values using the column's given comparator.
            final int compare = column.getComparator().compare(obj1.getValue(), obj2.getValue());
            // Sort by proper ascending or descending.
            return column.getSortType() == TableColumn.SortType.ASCENDING ? compare : -compare;
        }
    }
}

You can then sort at anytime with

Collections.sort(backingList, new TalbeColumnListComparator(table.getSortOrder());

I use this to sort multiple lists with the same sort, sort on background threads, do efficient updates without resorting the whole list, etc. I think there are going to be some improvements to table sorting in Javafx 8 so this won't be necessary in the future.

Upvotes: 2

Marco Jakob
Marco Jakob

Reputation: 1108

The example of fornacif works, but not if there is more than one sort order (try shift-click on a second column to create secondary sort order).

To do a re-sort on all columns you would need to do something like this:

List<TableColumn<Room, ?>> sortOrder = new ArrayList<>(roomTable.getSortOrder());
roomTable.getSortOrder().clear();
roomTable.getSortOrder().addAll(sortOrder);

Upvotes: 6

fornacif
fornacif

Reputation: 61

If your TableView is not reinitialized, you can also do the following:

TableColumn<BundleRow, ?> sortOrder = rooms.getSortOrder().get(0);
rooms.getSortOrder().clear();
rooms.getSortOrder().add(sortOrder);

Upvotes: 6

betaman
betaman

Reputation: 1895

Ok, I found how to do it. I will summarize it here in case it is useful to others:

Before you update the contents of the TableView, you must save the sortcolum (if any) and the sortType:

        TableView rooms;
        ...
        TableColumn sortcolumn = null;
        SortType st = null;
        if (rooms.getSortOrder().size()>0) {
            sortcolumn = (TableColumn) rooms.getSortOrder().get(0);
            st = sortcolumn.getSortType();
        }

Then, after you are done updating the data in the TableView, you must restore the lost sort-column state and perform a sort.

       if (sortcolumn!=null) {
            rooms.getSortOrder().add(sortcolumn);
            sortcolumn.setSortType(st);
            sortcolumn.setSortable(true); // This performs a sort
        }

I do not take into account the possibility of having multiple columns in the sort, but this would be very simple to do with this information.

Upvotes: 18

Related Questions