amru
amru

Reputation: 1398

How to override sort behaviour in TableView

My TableView populates data from database. When user clicks a column header, it sort the data based on it. This feature is out of the box. However, I have too many records to populate them at a time. Say I have 1000 records and the table only shows 500. When I sort it based on a column, it only shorts the 500 already populated record.

I'd like to override the sorting behaviour so when user clicks a column header, it will reload the data from database and provide necessary information for "order by" clause in the query. My problem is, I don't know

  1. How to turn off existing sorting behaviour. I can set column's sortable property to false, but I'm afraid it makes the header not clickable.
  2. How to attach listener to listen to column header click event. Is tableView.getSortOrder().addListener() the right way?

Upvotes: 6

Views: 4080

Answers (2)

Matjaz
Matjaz

Reputation: 484

I know it is a bit late but I just got to the same issue. Since I did not find solution online I did some digging and figured out that it is best to override sort() method. If you try to create EventHandler for OnSort, it will be fired after rows has been already sorted and refreshed. Since you probably want to directly show the results from database, it is best to ignore sorting of local data altogether.

So to do it properly just create some class that extends TableView. Then override sort method as below. To do some custom logic, just implement SortListener and set it through a setter. I hope it helps someone even after so many years.

public class OurTableView<S> extends TableView<S> {
    private SortListener sortListener;
    
    @Override
    public void sort() {
        if (sortListener!=null) {
            sortListener.sort();
        } else {
            super.sort();
        }
    }

    public void setSortListener(SortListener sortListener) {
        this.sortListener = sortListener;
    }

    public interface SortListener {
        void sort();
    }
}

Upvotes: 0

amru
amru

Reputation: 1398

I got an ugly solution that only solves a half of the problem. I can attach a listener to column header click event, but can't remove default TableView sorting behaviour.

private void initTable() {
    ...
    ...
    //listen to sorting type (ASC/DESC) change
    SortTypeChangeListener sortTypeChangeListener = new SortTypeChangeListener();
    clmName.sortTypeProperty().addListener(sortTypeChangeListener);
    clmGender.sortTypeProperty().addListener(sortTypeChangeListener);
    reload();

    //listen to sortorder change
    tblMember.getSortOrder().addListener(new ListChangeListener<TableColumn<VOMember, ?>>() {
        @Override
        public void onChanged(Change<? extends TableColumn<VOMember, ?>> change) {
            reload();
        }
    });
}

private void reload() {
  /**
     * Get sorted columns and sorting versus (ASC/DESC)
     */
    List<String> lstSortedColumn = new ArrayList<String>();
    List<String> lstSortedType = new ArrayList<String>();
    for (TableColumn<VOMember, ?> tc : tblMember.getSortOrder()) {
        PropertyValueFactory valFactory = (PropertyValueFactory) tc.getCellValueFactory();
        valFactory.getProperty();
        lstSortedColumn.add(valFactory.getProperty());
        lstSortedType.add(tc.getSortType().name());
    }

/**
     * Retrieve data from database. Pass the sorting information
     */        
    List<VOMember> lstMember = controller.retrieve(lstSortedColumn, lstSortedType);
    ObservableList<VOMember> data = FXCollections.observableList(lstMember);
    tblMember.setItems(data);
}

class SortTypeChangeListener implements InvalidationListener {

    @Override
    public void invalidated(Observable o) {
        /**
         * If the column is not in sortOrder list, just ignore.
         * It avoids intermittent duplicate reload() calling
         */
        TableColumn col = (TableColumn) ((SimpleObjectProperty) o).getBean();
        if (!tblMember.getSortOrder().contains(col)) {
            return;
        }

        reload();
    }
}

I'd like to hear your view/comment on this.

Upvotes: 2

Related Questions