JTable的单元格和表头写完之后,关于JTable就剩下排序和过滤了,对于过滤来说,简单的直接使用Sun的RowSorter就可以了,复杂的可以集成Lucence等排序工具,对于它来说,性能比实现更重要,有时间就开个专题写,没时间就不写了,这里主要写排序.
排序从界面表现看其实就是对JTableHeader的鼠标操作,引发TableModel的数值比较,最后表现到画面的过程,知道这个过程很重要,它可以帮助我们完全实现自己的排序过程.
对于Java的JTable排序来说,主要分为两个阶段:Java1.6以前和Java1.6版本:Java1.6之前想要实现JTable的话,必须自己实现TableSorter,然后对JTableHeader去注册,很麻烦,但是可以完全自己控制;Java1.6为了方便,Sun增加了排序和过滤的类:
javax.swing.table.
TableRowSorter<M extends TableModel> -à
javax.swing. DefaultRowSorter<M, I> -à
javax.swing. RowSorter<M>
我们可以直接使用了.
实现很容易,看Sun官方的例子:
RowSorter<TableModel> rowSorter = new TableRowSorter<TableModel>(table.getModel());
table.setRowSorter(rowSorter);
这是JTable就自动为你实现了过滤,它的好处是不污染任何的JTable数据和渲染,自然进行排序,结果如图:
 
但是对于默认的JTable来说, TableRowSorter的默认排序都是把数据当做Object来处理的,这时我们看表格的数据行:
 
对于年份来说,这个排序是不对的,这个时候我们必须要复写TableModel的getColumnClass方法,告诉TableRowSorter我们现在需要排序的数据类型, TableRowSorter就会根据类型给我们的列设置合适的比较器Comparator:
Collator.getInstance()
       @Override
        public Class<? extends Object> getColumnClass(int c) {
            return
getValueAt(0, c).getClass();
        }
这是对JTable的排序就完成了:
 
但有时候还有别的情况,比如我们单元格放置的是一个特殊组件, TableRowSorter根本没有合适的比较器给我们提供,或者是基本类型但是我们不希望使用默认的比较器Comparator,这个时候我们就需要自己实现一个Comparator,然后通过TableRowSorter的setComparator设置某一列一个新的比较器.比如我们希望我们的第二列按字符串的反序排序:
TableRowSorter<TableModel> rowSorter = new TableRowSorter<TableModel>(table.getModel());
    rowSorter.setComparator(1, new Comparator<String>() {
            @Override
            publicint compare(String str1, String str2) {
                return
-str1.compareTo(str2);
            }
        });
table.setRowSorter(rowSorter);
效果如图:
 
到此为止,Java1.6排序的基本使用就完成了,通过Sun的方法很简单就实现了.
Java1.6以前的JTable排序功能必须自己实现,Sun官方也提供了例子,当然在1.6里你也可以自己实现,但是自己实现必须考虑排序Model,排序状态,JTableHeader的状态和监听,还要自己写Header的Rnederer,所以不是不能用1.6的话,最好不要自己实现.先看看是如何实现的,因为是Sun官方给的例子,就大概写下,算是学习和回忆以前使用1.5自己写Sorter的日子了.
效果和1.6类似:
 
首先看TableSorter类,它继承AbstractTableModel,这样它也就相当于自己也是一种底层数据模型,可以记录数据和排序数据:
publicclass TableSorter extends
AbstractTableModel {
然后看它的属性:
    private
JTableHeader tableHeader;
这个是需要排序的JTable的Header,这里需要对它进行鼠标监听和状态管理.
    private
MouseListener mouseListener;
private
TableModelListener tableModelListener;
这两个是鼠标监听器和TableModel监听器,主要是当鼠标排序和JTabel数据变化时排序也随之变化.
    private
Map<Class<?>, Comparator<?>> columnComparators
        = new
HashMap<Class<?>, Comparator<?>>();
    private
List<Directive> sortingColumns
        = new
ArrayList<Directive>();
这连个主要是记录状态的,一个是记录列的排序比较器,一个是记录列的排序状态.
publicstaticfinal Comparator<Object> LEXICAL_COMPARATOR = new
Comparator<Object>() {
            publicint compare(Object o1, Object o2) {
                return o1.toString().compareTo(o2.toString());
            }
    };
另外还提供了几种基本的排序比较器,这是String的比较器.
然后是是构造函数,
public
TableSorter(TableModel tableModel) {
传入我们需要排序的JTable的TableModel,并对JTable增加事件监听和TableModel数据变化监听:
   this.tableHeader.addMouseListener(mouseListener);
   this.tableHeader.setDefaultRenderer(new SortableHeaderRenderer(
                    this.tableHeader.getDefaultRenderer()));
this.tableModel.addTableModelListener(tableModelListener);
然后处理这些监听:
    privateclass MouseHandler extends
MouseAdapter {
        @Override
        publicvoid mouseClicked(MouseEvent e) {
首先取得排序列和当前排序状态:
    JTableHeader h = (JTableHeader)
e.getSource();
            TableColumnModel columnModel =
h.getColumnModel();
    int viewColumn
= h.columnAtPoint(e.getPoint());
    int column =
columnModel.getColumn(viewColumn).getModelIndex();
int status = getSortingStatus(column);
然后判断后调用排序方法:
setSortingStatus(column, status);
TableModel数据变化监听也类似:
    privateclass TableModelHandler implements
TableModelListener {
        @Override
        publicvoid tableChanged(TableModelEvent e) {
非排序状态直接插入:
 if (!isSorting()) {
                clearSortingState();
                fireTableChanged(e);
                return;
 }
排序状态比较插入:
   int column = e.getColumn();
   if (e.getFirstRow() == e.getLastRow()
        && column != TableModelEvent.ALL_COLUMNS
        && getSortingStatus(column) == NOT_SORTED
        && modelToView != null) {
          int viewIndex =
getModelToView()[e.getFirstRow()];
          fireTableChanged(new TableModelEvent(TableSorter.this,
                        viewIndex, viewIndex, column,
e.getType()));
                return;
  }
然后是一个行的比较器:
    // Helper
classes
privateclass Row implements Comparable<Object> {
它取得比较的行:
        @Override
        publicint compareTo(Object o) {
            int row1 = modelIndex;
            int row2 =
((Row) o).modelIndex;
再去的比较的值:
      Object o1 = tableModel.getValueAt(row1,
column);
      Object o2 = tableModel.getValueAt(row2,
column);
根据我们提供的构造器比较:
comparison =
getComparator(column).compare(o1, o2);
其它的还有一些设置比较器,设置JTableHeader的Renderer,绘制排序的图标的方法,基本都是以前JTable会学习到的,就不写了,很多但是不难.
然后是使用,先创建我们自己构造的TableSorter:
TableSorter sorter = new
TableSorter(new MyTableModel());
当做JTable的TableModel放入JTable中:
JTable table = new
JTable(sorter);
还要设置一下Header,目的是使用我们自己做成的HeaderRenderer,可以出现图标
sorter.setTableHeader(table.getTableHeader());
以后就和正常JTable一样了.
最后,我们看一个我们自己实现排序比较和Renderer的例子:

 
工程目录如下:
 
其中和类是实现了Icon接口的绘制JTableHeader排序时的图片的类,
publicclass MyBlankIcon implements Icon {
publicclass MySortIcon implements Icon {
主要过程就是实现paintIcon方法绘制图片,前面写过这种三角形形式的图片绘制方法了,这里省略.
void paintIcon(Component c, Graphics g, int x, int y);
然后就是比较重要的MyTableSorter类,它继承TableRowSorter,扩充了我们自己的排序实现:
publicclass MyTableSorter extends
TableRowSorter<TableModel> {
提供了三个方法,正序、逆序和无序:
    /**
     * Enumeration value indicating the items
are sorted in increasing
     */
    protectedvoid setASCSort(int colIdx) {
        ArrayList<SortKey> key = new ArrayList<SortKey>();
        key.add(new
RowSorter.SortKey(colIdx, SortOrder.ASCENDING));
        setSortKeys(key);
    }
    /**
     * Enumeration value indicating the items
are sorted in decreasing * order.
     */
    protectedvoid setDESCSort(int colIdx) {
        ArrayList<SortKey> key = new ArrayList<SortKey>();
        key.add(new RowSorter.SortKey(colIdx,
SortOrder.DESCENDING));
        setSortKeys(key);
    }
    /**
     * Enumeration value indicating the items
are unordered.
     */
    protectedvoid setUNSort(int colIdx) {
        ArrayList<SortKey> key = new ArrayList<SortKey>();
        key.add(new
RowSorter.SortKey(colIdx, SortOrder.UNSORTED));
        setSortKeys(key);
    }
提供设置当前排序状态的方法:
    protectedvoid setSorterStatus(int column, boolean CtrlDown) {
    List<SortKey>
SortStatus = new ArrayList<SortKey>(getSortKeys());
        SortKey sortKey = null;
        int sortIndex =
-1;
        for (sortIndex
= SortStatus.size() - 1; sortIndex >= 0; sortIndex--) {
            if
(SortStatus.get(sortIndex).getColumn() == column) {
                break;
            }
        }
        if (sortIndex == -1) {
            // Key doesn't exist
            if (CtrlDown)
{
                sortKey = new SortKey(column, SortOrder.DESCENDING);
            } else {
                sortKey = new SortKey(column, SortOrder.ASCENDING);
            }
            SortStatus.add(0, sortKey);
        } elseif (sortIndex == 0) {
            // It's the primary sorting key, toggle it
            SortStatus.set(0,
toggle(SortStatus.get(0), CtrlDown));
        } else {
            // It's not the first, but was sorted on, remove old
            // entry, insert as first with ascending.
            SortStatus.remove(sortIndex);
            if (CtrlDown)
{
                sortKey = new SortKey(column, SortOrder.DESCENDING);
            } else {
                sortKey = new SortKey(column, SortOrder.ASCENDING);
            }
            SortStatus.add(0, sortKey);
        }
        if
(SortStatus.size() > getMaxSortKeys()) {
            SortStatus = SortStatus.subList(0,
getMaxSortKeys());
        }
        setSortable(column, true);
        setSortKeys(SortStatus);
        setSortable(column, false);
    }
提供取得下一个状态的方法:
    protected SortKey
toggle(SortKey key, boolean CtrlDown) {
        if
(key.getSortOrder() == SortOrder.ASCENDING) {
         returnnew SortKey(key.getColumn(), SortOrder.DESCENDING);
        } elseif (key.getSortOrder() == SortOrder.DESCENDING) {
            returnnew SortKey(key.getColumn(), SortOrder.UNSORTED);
        } else {
            returnnew SortKey(key.getColumn(), SortOrder.ASCENDING);
        }
    }
然后就是Renderer方法了,它继承TableCellRenderer,设置排序状态和Header状态:
publicclass MyHeaderButtonRenderer extends JButton implements
        TableCellRenderer, MouseListener {
它提供一个属性存储当前列的排序状态:
    /** save
the header state. */
    private
Hashtable<Integer, Integer> state = null;
在它的鼠标事件里,设置排序和排序状态:
    /**
     * Invoked when the mouse button has been
clicked (pressed and
 * released) on a component.
     */
    @Override
    publicvoid mouseClicked(MouseEvent e) {
先取得鼠标事件的列,设置表现:
      int col = header.columnAtPoint(e.getPoint());
      int sortCol = header.getTable().convertColumnIndexToModel(col);
      renderer.setPressedColumn(col);
      renderer.setSelectedColumn(col);
      header.repaint();
再设置排序和状态:
if (header.getTable().isEditing()) {
             header.getTable().getCellEditor().stopCellEditing();
      }
      if (!(DOWN == renderer.getState(col))
               && !(UP == renderer.getState(col))) {
            sorter.setUNSort(sortCol);
      }
实现TableCellRenderer的方法设置列的Header的表现:
@Override
public Component
getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (header != null && renderer != null) {
            boolean isPressed =
(column == pushedColumn);
           
button.getModel().setPressed(isPressed);
            button.getModel().setArmed(isPressed);
        }
使用也不是很麻烦:
先创建Sorter:
TableSorter tableSorter = new MyTableSorter(table);
设置某一列的比较器,和TableSorter一样:
tableSorter.setComparator(2, new MyComparator<String>());
 table.setRowSorter(tableSorter);
然后是创建Renderer:
MyHeaderButtonRenderer renderer = new MyHeaderButtonRenderer();
然后设置JTable的Header的Renderer:
 table.getColumnModel().getColumn(i).setHeaderRenderer(renderer);
这样就完成了.