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:

JTable unsorted

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:

JTable sorted by one column

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:

JTable sorted by two columns

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:

JTable sorting one colum keeps order

 

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:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (JTableSortingExample.zip)JTableSortingExample.zip[Java source code]3 kB

Add comment

   


Comments 

#22GEORGE2024-08-10 01:55
GOOD EXPLAIN IS VERY GOOD WE NEED A VIDIO TO BE MORE EFFICTIVE
Quote
#21shubham2023-08-25 07:35
I want to add and show filter at each header in Jtable.
Please create some utility or give pointer to do same.
Quote
#20Mike2023-02-26 17:59
Can you add a column that provides a running total of employee age such that when other columns are sorted, the cumulative age remains correct? Example:
1 Sam analyst 50 50
2 Hess Designer 31 81
...
Quote
#19Alexander2020-08-11 11:19
TableRowSorter(jTable.model) {
override fun getSortKeys(): List {
Quote
#18Sabrina2020-06-10 22:27
Thank you so much for this simple and clear tutorial! Helped me a lot :)
Quote