12.11.4 实现排序
使用JTable
实现的表格并没有实现根据指定列排序的功能,但开发者可以利用AbstractTableModel
类来实现该功能。由于TableModel
不强制要求保存表格里的数据,只要TableModel
实现了getValueAt()
,getColumnCount()
和getRowCount()
三个方法,JTable
就可以根据该TableModel
生成表格。因此可以创建个SortableTableModel
实现类,它可以将原TableModel
包装起来,并实现根据指定列排序的功能。
程序创建的SortableTableModel
实现类会对原TableModel
进行包装,但它实际上并不保存仼何数据,它会把所有的方法实现委托给原TableModel
完成。SortableTableModel
仅保存原TableModel
里每行的行索引,当程序对SortableTableModel
的指定列排序时,实际上仅仅对SortableTableModel
里的行索引进行排序,这样造成的结果是:SortableTableModel
里的数据行的行索引与原TableModel
里数据行的行索引不一致,所以对于TableModel
的那些涉及行索引的方法都需要进行相应的转换。
程序 表格排序
下面程序实现了SortableTableModel
类,并使用该类来实现对表格根据指定列排序的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
| import java.awt.event.*; import javax.swing.*; import javax.swing.table.*;
public class SortTable { JFrame jf = new JFrame("可按列排序的表格"); Object[][] tableData = { new Object[]{"李清照" , 29 , "女"}, new Object[]{"苏格拉底", 56 , "男"}, new Object[]{"李白", 35 , "男"}, new Object[]{"弄玉", 18 , "女"}, new Object[]{"虎头" , 2 , "男"} }; Object[] columnTitle = {"姓名" , "年龄" , "性别"}; JTable table = new JTable(tableData , columnTitle); SortableTableModel sorterModel = new SortableTableModel( table.getModel()); public void init() { table.setModel(sorterModel); table.getTableHeader().addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent event) { if (event.getClickCount() < 2) { return; } int tableColumn = table.columnAtPoint(event.getPoint()); int modelColumn = table.convertColumnIndexToModel(tableColumn); sorterModel.sort(modelColumn); } }); jf.add(new JScrollPane(table)); jf.pack(); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.setVisible(true); } public static void main(String[] args) { new SortTable().init(); } } class SortableTableModel extends AbstractTableModel { private TableModel model; private int sortColumn; private Row[] rows; public SortableTableModel(TableModel m) { model = m; rows = new Row[model.getRowCount()]; for (int i = 0; i < rows.length; i++) { rows[i] = new Row(i); } } public void sort(int c) { sortColumn = c; java.util.Arrays.sort(rows); fireTableDataChanged(); } public Object getValueAt(int r, int c) { return model.getValueAt(rows[r].index, c); } public boolean isCellEditable(int r, int c) { return model.isCellEditable(rows[r].index, c); } public void setValueAt(Object aValue, int r, int c) { model.setValueAt(aValue, rows[r].index, c); } public int getRowCount() { return model.getRowCount(); } public int getColumnCount() { return model.getColumnCount(); } public String getColumnName(int c) { return model.getColumnName(c); } public Class getColumnClass(int c) { return model.getColumnClass(c); } private class Row implements Comparable<Row> { public int index; public Row(int index) { this.index = index; } public int compareTo(Row other) { Object a = model.getValueAt(index, sortColumn); Object b = model.getValueAt(other.index, sortColumn); if (a instanceof Comparable) { return ((Comparable)a).compareTo(b); } else { return a.toString().compareTo(b.toString()); } } } }
|
上面程序是在SimpleTable
程序的基础上改变而来的,改变的部分就是增加了两行粗体字代码和①号粗体字代码块。其中粗体字代码负责把原JTable
的model
对象包装成SortableTableModel
实例,并设置原JTable
使用SortableTableModel
实例作为对应的mode
对象;
而①号粗体字代码部分则用于为该表格的列头增加鼠标监听器:当用鼠标双击指定列时,SortableTableModel
对象根据指定列进行排序。
程序中还使用了convertColumnIndexToModel()
方法把JTable
中的列索引转换成TableModel
中的列索引。这是因为JTable
中的列允许用户随意拖动,因此可能造成JTable
中的列索引与TableModel
中的列索引不一致。
运行上面程序,并双击“年龄”列头,将看到如图12.53所示的排序效果。
实际上,上面程序的关键在于SortableTableModel
类,该类使用rows
数组来保存原TableModel
里的行索引。为了让程序可以对rows
数组元素根据指定列排序,程序使用了Row
类来封装行索引,并实现了compareTo()
方法,该方法实现了根据指定列来比较两行大小的功能,从而允许程序根据指定列对rows
[数组元素进行排序。