Sort table rows

Sorting table rows is a common task in Swing applications. The simplest way involves a call to a single method, JTable.setAutoCreateRowSorter(true). This will attach a generic sorter to your table. The sorting is controlled by clicking on the column headers.

Example

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collections;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;

public class GenericTableSort {

  /** Simplest way to add sorting to a table. */
  public static void main(String... aArgs){
    GenericTableSort app = new GenericTableSort();
    app.buildAndDisplayGui();
  }
 
  // PRIVATE 

  private void buildAndDisplayGui(){
    JFrame frame = new JFrame("Test Generic Table Sort"); 
    addSortableTableTo(frame);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
 
  private void addSortableTableTo(JFrame aFrame){
    JPanel panel = new JPanel();
    
    Object[][] data = { {1,"T"},   {2,"B"},  {3,"A"},  {4, "F"}};
    String[] cols = {"One", "Two"};
    final JTable table = new JTable(data, cols);
    
    table.setAutoCreateRowSorter(true); //a generic sorter
    //without the scroll pane, you won't see the headers
    panel.add(new JScrollPane(table));
   
    JButton revert = new JButton("Revert Sort");
    revert.addActionListener( new ActionListener(){
      @Override public void actionPerformed(ActionEvent aEvent) {
         List<RowSorter.SortKey> NO_SORT = Collections.emptyList();
         table.getRowSorter().setSortKeys(NO_SORT);
       }
    });
    panel.add(revert);
   
    aFrame.getContentPane().add(panel);      
  }
}
 

The above example unsorts the table when a button is clicked. To unsort a table, and revert it back to its original state, you simply pass a null or empty List to this method:

table.getRowSorter().setSortKeys(List)

Custom sorting with SortKeys

In some cases, you may want more control over sorting. For example, you may need to implement a sort that depends on more than one column (a common requirement). One option is to use a list of SortKey objects to control the sorting.

Example:

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

public class TableSortWithSortKey {

  /** Custom table sorting, using SortKey. */
  public static void main(String... aArgs){
    TableSortWithSortKey app = new TableSortWithSortKey();
    app.buildAndDisplayGui();
  }
 
  // PRIVATE 

  private JTable fTable;
  private RowSorter<TableModel> fSorter;
  
  private void buildAndDisplayGui(){
    JFrame frame = new JFrame("Test Table Sort With Sort Key"); 
    addSortableTableTo(frame);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
 
  private void addSortableTableTo(JFrame aFrame){
    JPanel panel = new JPanel();
    
    Object[][] data = { {1,"T"},   {2,"B"},  {3,"A"},  {4, "F"}};
    String[] cols = {"One", "Two"};
    fTable = new JTable(data, cols);
    
    fSorter = new TableRowSorter<>(fTable.getModel());
    fTable.setRowSorter(fSorter);
    fTable.getTableHeader().addMouseListener(new CustomSorter());

    panel.add(new JScrollPane(fTable));
    aFrame.getContentPane().add(panel);      
  }
  
  /** Default sort behaviour, plus every third click removes the sort. */
  private final class CustomSorter extends MouseAdapter {
    @Override public void mouseClicked(MouseEvent aEvent) {
      int columnIdx = fTable.getColumnModel().getColumnIndexAtX(aEvent.getX());
      //build a list of sort keys for this column, and pass it to the sorter
      //you can build the list to fit your needs here 
      //for example, you can sort on multiple columns, not just one
      List<RowSorter.SortKey> sortKeys = new ArrayList<>();
      //cycle through all orders; sort is removed every 3rd click
      SortOrder order =  SortOrder.values()[fCountClicks % 3];
      sortKeys.add(new RowSorter.SortKey(columnIdx, order));
      fSorter.setSortKeys(sortKeys);
      ++fCountClicks;
    }
    private int fCountClicks;
  }
} 

Custom sorting with Comparators

Here's another option for implementing a custom sort. The advantage of this technique is that it's controlled by the arbitrary Comparators that you define. A disadvantage is that there's no visual indicator for the selected sort on the column header.

First, define the different Comparators you need, perhaps directly in your Model Object. (These Comparators know nothing about the user interface, but they are ultimately responsible for the actual sorting.) Then it becomes a case of wiring together clicks on the column header to the proper Comparator, sorting the data underlying your TableModel, and then refreshing the screen.

More precisely:

Here's a snippet for the first steps:
myTable.getTableHeader().addMouseListener(new MySorter());

private final class MySorter extends MouseAdapter {
  @Override public void mouseClicked(MouseEvent aEvent) {
    int colIdx = myTable.getColumnModel().getColumnIndexAtX(aEvent.getX());
    myTableModel.sortByColumn(colIdx);
  }
}
The above technique is implemented by the Movies app, using the following classes:

See Also :
Type Safe Enumerations
Filter table rows