Java Swing JTable开启排序功能只需一个调用:
JTable table = new JTable();
table.setAutoCreateRowSorter(true);
但这个排序功能只支持单列排序,而多列排序需要自己实现。
本文内容是使用sorter和renderer实现点击表头进行多列排序,第一次点击的列作为主排序列,后点击的列作为次排序列。建议在开始阅读本文前可以看看官方教程《How to Use Tables》,对JTable的sorter和renderer有个概念。
分析
TableRowSorter对象已经提供了多列排序的功能:
TableRowSorter sorter
= new TableRowSorter(table.getModel());
table.setRowSorter(sorter);
List sortKeys
= new ArrayList();
sortKeys.add(new RowSorter.SortKey(1, SortOrder.ASCENDING));
sortKeys.add(new RowSorter.SortKey(0, SortOrder.ASCENDING));
sorter.setSortKeys(sortKeys); // 执行排序
上面是把第1列作为主排序列升序排序,把第0列作为次排序列降序排序。
表格的表头由JTableHeader对象维护,该对象里维护着BaseTableHeaderUI对象,这个对象里设置了mouseInputListener监听器进行监听,当点击表头后就通知该监听器调用sorter.toggleSortOrder方法进行排序。所以我们需要继承TableRowSorter类重写toggleSortOrder方法实现自己的排序逻辑。
另一个要考虑的就是表头的上下箭头显示,用于显示该列是升序或降序排序。
JTableHeader对象默认使用DefaultTableCellHeaderRenderer对象作为表头Renderer,Renderer的getTableCellRendererComponent方法里设置上下箭头图标并返回用于显示表头单元格的组件,而该方法里调用的getColumnSortOrder方法只会返回主排序列的排序顺序,通过该方法的返回值只能显示主排序列的箭头。所以需要重写DefaultTableCellHeaderRenderer对象的相关方法实现让多个列显示上下箭头,再通过JTable的getTableHeader().setDefaultRenderer(TableCellRenderer defaultRenderer)方法指定我们的表头Renderer)
实现
通过上面的分析,我们通过编写自己的sorter和renderer实现多列排序。
代码与相关注释(在JDK8下测试运行):
TableSortDemo.java:
package com.test.sort;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class TableSortDemo extends JPanel {
public TableSortDemo() {
super(new GridLayout(1, 0));
JTable table = new JTable(new AbstractTableModel() {
private String[] columnNames = {"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"};
private Object[][] data = {
{"Kathy", "Smith",
"Snowboarding", new Integer(10), new Boolean(false)},
{"John", "Doe",
"Rowing", new Integer(3), new Boolean(true)},
{"Sue", "White",
"Knitting", new Integer(2), new Boolean(false)},
{"Kathy", "White",
"Speed reading", new Integer(20), new Boolean(true)},
{"Joe", "Brown",
"Pool", new Integer(10), new Boolean(true)}
};
public in