6 Techniques for Sorting JTable You Should Know
- Details
- Written by Nam Ha Minh
- Last Updated on 04 July 2019   |   Print Email
JTable is a flexible Swing component which is very well-suited at displaying data in a tabular format. Sorting rows by columns is a nice feature provided by the JTable class. In this tutorial, you will learn some fundamental techniques for sorting rows in JTable, from enable sorting, sort a column programmatically to listen to sorting event.
To demonstrate sorting in JTable, we create a simple Swing program that displays a list of employees. Hence we have the Employee class:
package net.codejava.swing.jtable; /** * * @author www.codejava.net * */ public class Employee { private int index; private String name; private String job; private int age; public Employee(String name, String job, int age) { this.name = name; this.job = job; this.age = age; } // getters and setters are hidden for brevity }
It’s recommended to create a separate table model in order to make the sorting working properly. Thus we create the following TableModel class:
package net.codejava.swing.jtable; import java.util.List; import javax.swing.table.AbstractTableModel; /** * A table model implementation for a list of Employee objects. * @author www.codejava.net * */ public class EmployeeTableModel extends AbstractTableModel { private static final int COLUMN_NO = 0; private static final int COLUMN_NAME = 1; private static final int COLUMN_JOB = 2; private static final int COLUMN_AGE = 3; private String[] columnNames = {"No #", "Name", "Job", "Age"}; private List<Employee> listEmployees; public EmployeeTableModel(List<Employee> listEmployees) { this.listEmployees = listEmployees; int indexCount = 1; for (Employee employee : listEmployees) { employee.setIndex(indexCount++); } } @Override public int getColumnCount() { return columnNames.length; } @Override public int getRowCount() { return listEmployees.size(); } @Override public String getColumnName(int columnIndex) { return columnNames[columnIndex]; } @Override public Class<?> getColumnClass(int columnIndex) { if (listEmployees.isEmpty()) { return Object.class; } return getValueAt(0, columnIndex).getClass(); } @Override public Object getValueAt(int rowIndex, int columnIndex) { Employee employee = listEmployees.get(rowIndex); Object returnValue = null; switch (columnIndex) { case COLUMN_NO: returnValue = employee.getIndex(); break; case COLUMN_NAME: returnValue = employee.getName(); break; case COLUMN_JOB: returnValue = employee.getJob(); break; case COLUMN_AGE: returnValue = employee.getAge(); break; default: throw new IllegalArgumentException("Invalid column index"); } return returnValue; } @Override public void setValueAt(Object value, int rowIndex, int columnIndex) { Employee employee = listEmployees.get(rowIndex); if (columnIndex == COLUMN_NO) { employee.setIndex((int) value); } } }
For sorting, the important point here is the method getColumnClass():
@Override public Class<?> getColumnClass(int columnIndex) { if (listEmployees.isEmpty()) { return Object.class; } return getValueAt(0, columnIndex).getClass(); }
It’s because, by default, the JTable sorts a column by comparing String values returned from row objects of that column. Therefore, if the table contains a column that stores only integer numbers, then default sorting behavior is comparing String values instead of number values, which is wrong. If we have the getColumnClass() method returns class type of each column in the table, then the table knows exact type of the column in advance to implement correct sorting behavior for that column. For example, if the getColumnClass() method returns Integer.class for a numeric column, then the table will sort that column by comparing numbers, not by Strings (default).
The following code is for the demo program:
package net.codejava.swing.jtable; import java.awt.BorderLayout; import java.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.table.TableModel; /** * This program demonstrates how to sort rows in a table. * @author www.codejava.net * */ public class JTableSortingExample extends JFrame { private JTable table; public JTableSortingExample() { super("JTable Sorting Example"); List<Employee> listEmployees = createListEmployees(); TableModel tableModel = new EmployeeTableModel(listEmployees); table = new JTable(tableModel); // insert code for sorting here... add(new JScrollPane(table), BorderLayout.CENTER); pack(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); } public List<Employee> createListEmployees() { List<Employee> listEmployees = new ArrayList<>(); // code to add dummy data here... return listEmployees; } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new JTableSortingExample().setVisible(true); } }); } }
Running this program would produce the following screen:
Let’s try to sort the table by clicking on the header column “Name”, but nothing happens. That’s right, because sorting is not enabled by default. Now, let’s see how to enable sorting for this table.
1. Enable Sorting for JTable
Use the following simple statement to enable default sorting for the table:
table.setAutoCreateRowSorter(true);
Now, run the demo program again and click on the header of the column “Name”. We see rows in the table are sorted by that column in ascending order, and vice-versa if we click again:
Now, the user can click on any column header to sort data in the table by that column. It’s pretty easy, isn’t it? However, do you notice that the table doesn’t get sorted when the program launches. How can we get the table sorted by default? The answer is described in the next section right below.
2. Sorting JTable by a specific column programmatically
To sort the table by a column programmatically, we need to create a TableRowSorter and a SortKey that specifies the column index (by which the table is sorted) and sorting order (ascending or descending). For example, the following code snippet sorts the 2nd column (at 1-index) into ascending order:
TableRowSorter<TableModel> sorter = new TableRowSorter<>(table.getModel()); table.setRowSorter(sorter); List<RowSorter.SortKey> sortKeys = new ArrayList<>(); int columnIndexToSort = 1; sortKeys.add(new RowSorter.SortKey(columnIndexToSort, SortOrder.ASCENDING)); sorter.setSortKeys(sortKeys); sorter.sort();
If you want to sort the column into descending order:
sortKeys.add(new RowSorter.SortKey(columnIndexToSort, SortOrder.DESCENDING));
3. Sorting JTable by multiple columns
Sometimes, we need to sort data in the table by more than one column. For example, in the above table, we can sort data first by job and second by name. To do so, just add another SortKey to the list of SortKeys:
int columnIndexForJob = 2; sortKeys.add(new RowSorter.SortKey(columnIndexForJob, SortOrder.ASCENDING)); int columnIndexForName = 1; sortKeys.add(new RowSorter.SortKey(columnIndexForName, SortOrder.ASCENDING));
Here, which column is sorted first, which is sorted after is determined by the order of the SortKey added to the list.
Run the program again, we see the table is now sorted by the Job column first, then for the same values in the Job column, the values in the Name column are sorted after. The following screenshot shows the result:
Do you notice that the column No # is also re-ordered when we sort a column? It’s normal. But what if we want this column to keep order of its elements regardless of which column is stored? Let’s see the answer below.
4. Listening to JTable sorting event
It’s possible to get notified when the sorter order gets changed, i.e. when the user sorts another column or sort the same column into the reverse order. To do so, add a RowSorterListener handler for the table’s RowSorter:
sorter.addRowSorterListener(new RowSorterListener() { @Override public void sorterChanged(RowSorterEvent evt) { // code to handle sort order changes here... } });
For the above demo program, we want the column No # to keeps the same order all time, so we put code to re-update this column whenever the sort order gets changed:
sorter.addRowSorterListener(new RowSorterListener() { @Override public void sorterChanged(RowSorterEvent evt) { int indexOfNoColumn = 0; for (int i = 0; i < table.getRowCount(); i++) { table.setValueAt(i + 1, i, indexOfNoColumn); } } });
Run the program again, we see the column No # always keeps order, regardless of which column is currently sorted:
5. Disable sorting for a specific column in JTable
Use the following statement to turn off sorting functionality for a specific column:
sorter.setSortable(int column, boolean sortable);
For example, in the above program, the first column (0-index) doesn’t need to be sortable. Thus:
sorter.setSortable(0, false);
Try to click on the first column header, and we see that sorting is disabled on that column.
6. Using external Comparator to sort a specific column in JTable
By default, the TableRowSorter does the sorting by comparing values returned from compareTo() method of the object whose type is identified by the column class returned by TableModel.getColumnClass() method in the table model class. The returned class must implement the Comparable interface and its compareTo() method.
In our demo program, the Employee class declares properties of type String and Integer which already implements the Comparable interface. If you use non-standard types, remember to have your types implemented the Comparable so that your data can be sorted correctly.
In addition, the TableRowSorter allows us to specify our own comparator to sort a specific column via the setComparator(columnIndex, Comparator) method. Here’s an example:
sorter.setComparator(columnIndexForName, new Comparator<String>() { @Override public int compare(String name1, String name2) { return name1.compareTo(name2); } });
That sets a comparator which is used when sorting the second column (Name). Note that the setComparator() method discards the default comparator of the object of type returned by TableModel.getColumnClass() method.
JTable API References:
Related JTable Tutorials:
- A Simple JTable Example for Display
- Editable JTable Example
- JTable Simple Renderer Example
- JTable column header custom renderer examples
- How to scroll JTable row to visible area programmatically
- JTable popup menu example
- Setting column width and row height for JTable
- How to handle mouse clicking event on JTable column header
- How to create JComboBox cell editor for JTable
Comments
Please create some utility or give pointer to do same.
1 Sam analyst 50 50
2 Hess Designer 31 81
...
override fun getSortKeys(): List {