JTable的排序是一个让人头疼的问题,Sun没有为排序这个最常用的功能提供类。

但是近日翻看Sun官方java的tutorial,却发现其在文档中提供了这个类的实现,使用非常简单!

使用方法示例:

TableSorter sorter = new TableSorter(new MyTableModel()); //ADDED THIS

//JTable table = new JTable(new MyTableModel()); //OLD

JTable table = new JTable(sorter); //NEW

sorter.setTableHeader(table.getTableHeader()); //ADDED THIS

我把TableSorter类贴出来,自己编译就可以使用了

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import java.util.List;

import javax.swing.*;

import javax.swing.event.TableModelEvent;

import javax.swing.event.TableModelListener;

import javax.swing.table.*;

/**

* TableSorter is a decorator for TableModels; adding sorting

* functionality to a supplied TableModel. TableSorter does

* not store or copy the data in its TableModel; instead it maintains

* a map from the row indexes of the view to the row indexes of the

* model. As requests are made of the sorter (like getValueAt(row, col))

* they are passed to the underlying model after the row numbers

* have been translated via the internal mapping array. This way,

* the TableSorter appears to hold another copy of the table

* with the rows in a different order.

*

* TableSorter registers itself as a listener to the underlying model,

* just as the JTable itself would. Events recieved from the model

* are examined, sometimes manipulated (typically widened), and then

* passed on to the TableSorter's listeners (typically the JTable).

* If a change to the model has invalidated the order of TableSorter's

* rows, a note of this is made and the sorter will resort the

* rows the next time a value is requested.

*

* When the tableHeader property is set, either by using the

* setTableHeader() method or the two argument constructor, the

* table header may be used as a complete UI for TableSorter.

* The default renderer of the tableHeader is decorated with a renderer

* that indicates the sorting status of each column. In addition,

* a mouse listener is installed with the following behavior:

*

*

* Mouse-click: Clears the sorting status of all other columns

* and advances the sorting status of that column through three

* values: {NOT_SORTED, ASCENDING, DESCENDING} (then back to

* NOT_SORTED again).

*

* SHIFT-mouse-click: Clears the sorting status of all other columns

* and cycles the sorting status of the column through the same

* three values, in the opposite order: {NOT_SORTED, DESCENDING, ASCENDING}.

*

* CONTROL-mouse-click and CONTROL-SHIFT-mouse-click: as above except

* that the changes to the column do not cancel the statuses of columns

* that are already sorting - giving a way to initiate a compound

* sort.

*

*

* This is a long overdue rewrite of a class of the same name that

* first appeared in the swing table demos in 1997.

*

* @author Philip Milne

* @author Brendon McLean

* @author Dan van Enckevort

* @author Parwinder Sekhon

* @version 2.0 02/27/04

*/

public class TableSorter extends AbstractTableModel {

protected TableModel tableModel;

public static final int DESCENDING = -1;

public static final int NOT_SORTED = 0;

public static final int ASCENDING = 1;

private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);

public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() {

public int compare(Object o1, Object o2) {

return ((Comparable) o1).compareTo(o2);

}

};

public static final Comparator LEXICAL_COMPARATOR = new Comparator() {

public int compare(Object o1, Object o2) {

return o1.toString().compareTo(o2.toString());

}

};

private Row[] viewToModel;

private int[] modelToView;

private JTableHeader tableHeader;

private MouseListener mouseListener;

private TableModelListener tableModelListener;

private Map columnComparators = new HashMap();

private List sortingColumns = new ArrayList();

public TableSorter() {

this.mouseListener = new MouseHandler();

this.tableModelListener = new TableModelHandler();

}

public TableSorter(TableModel tableModel) {

this();

setTableModel(tableModel);

}

public TableSorter(TableModel tableModel, JTableHeader tableHeader) {

this();

setTableHeader(tableHeader);

setTableModel(tableModel);

}

private void clearSortingState() {

viewToModel = null;

modelToView = null;

}

public TableModel getTableModel() {

return tableModel;

}

public void setTableModel(TableModel tableModel) {

if (this.tableModel != null) {

this.tableModel.removeTableModelListener(tableModelListener);

}

this.tableModel = tableModel;

if (this.tableModel != null) {

this.tableModel.addTableModelListener(tableModelListener);

}

clearSortingState();

fireTableStructureChanged();

}

public JTableHeader getTableHeader() {

return tableHeader;

}

public void setTableHeader(JTableHeader tableHeader) {

if (this.tableHeader != null) {

this.tableHeader.removeMouseListener(mouseListener);

TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();

if (defaultRenderer instanceof SortableHeaderRenderer) {

this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);

}

}

this.tableHeader = tableHeader;

if (this.tableHeader != null) {

this.tableHeader.addMouseListener(mouseListener);

this.tableHeader.setDefaultRenderer(

new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));

}

}

public boolean isSorting() {

return sortingColumns.size() != 0;

}

private Directive getDirective(int column) {

for (int i = 0; i < sortingColumns.size(); i++) {

Directive directive = (Directive)sortingColumns.get(i);

if (directive.column == column) {

return directive;

}

}

return EMPTY_DIRECTIVE;

}

public int getSortingStatus(int column) {

return getDirective(column).direction;

}

private void sortingStatusChanged() {

clearSortingState();

fireTableDataChanged();

if (tableHeader != null) {

tableHeader.repaint();

}

}

public void setSortingStatus(int column, int status) {

Directive directive = getDirective(column);

if (directive != EMPTY_DIRECTIVE) {

sortingColumns.remove(directive);

}

if (status != NOT_SORTED) {

sortingColumns.add(new Directive(column, status));

}

sortingStatusChanged();

}

protected Icon getHeaderRendererIcon(int column, int size) {

Directive directive = getDirective(column);

if (directive == EMPTY_DIRECTIVE) {

return null;

}

return new Arrow(directive.direction == DESCENDING, size, sortingColumns.indexOf(directive));

}

private void cancelSorting() {

sortingColumns.clear();

sortingStatusChanged();

}

public void setColumnComparator(Class type, Comparator comparator) {

if (comparator == null) {

columnComparators.remove(type);

} else {

columnComparators.put(type, comparator);

}

}

protected Comparator getComparator(int column) {

Class columnType = tableModel.getColumnClass(column);

Comparator comparator = (Comparator) columnComparators.get(columnType);

if (comparator != null) {

return comparator;

}

if (Comparable.class.isAssignableFrom(columnType)) {

return COMPARABLE_COMAPRATOR;

}

return LEXICAL_COMPARATOR;

}

private Row[] getViewToModel() {

if (viewToModel == null) {

int tableModelRowCount = tableModel.getRowCount();

viewToModel = new Row[tableModelRowCount];

for (int row = 0; row < tableModelRowCount; row++) {

viewToModel[row] = new Row(row);

}

if (isSorting()) {

Arrays.sort(viewToModel);

}

}

return viewToModel;

}

public int modelIndex(int viewIndex) {

return getViewToModel()[viewIndex].modelIndex;

}

private int[] getModelToView() {

if (modelToView == null) {

int n = getViewToModel().length;

modelToView = new int[n];

for (int i = 0; i < n; i++) {

modelToView[modelIndex(i)] = i;

}

}

return modelToView;

}

// TableModel interface methods

public int getRowCount() {

return (tableModel == null) ? 0 : tableModel.getRowCount();

}

public int getColumnCount() {

return (tableModel == null) ? 0 : tableModel.getColumnCount();

}

public String getColumnName(int column) {

return tableModel.getColumnName(column);

}

public Class getColumnClass(int column) {

return tableModel.getColumnClass(column);

}

public boolean isCellEditable(int row, int column) {

return tableModel.isCellEditable(modelIndex(row), column);

}

public Object getValueAt(int row, int column) {

return tableModel.getValueAt(modelIndex(row), column);

}

public void setValueAt(Object aValue, int row, int column) {

tableModel.setValueAt(aValue, modelIndex(row), column);

}

// Helper classes

private class Row implements Comparable {

private int modelIndex;

public Row(int index) {

this.modelIndex = index;

}

public int compareTo(Object o) {

int row1 = modelIndex;

int row2 = ((Row) o).modelIndex;

for (Iterator it = sortingColumns.iterator(); it.hasNext();) {

Directive directive = (Directive) it.next();

int column = directive.column;

Object o1 = tableModel.getValueAt(row1, column);

Object o2 = tableModel.getValueAt(row2, column);

int comparison = 0;

// Define null less than everything, except null.

if (o1 == null && o2 == null) {

comparison = 0;

} else if (o1 == null) {

comparison = -1;

} else if (o2 == null) {

comparison = 1;

} else {

comparison = getComparator(column).compare(o1, o2);

}

if (comparison != 0) {

return directive.direction == DESCENDING ? -comparison : comparison;

}

}

return 0;

}

}

private class TableModelHandler implements TableModelListener {

public void tableChanged(TableModelEvent e) {

// If we're not sorting by anything, just pass the event along.

if (!isSorting()) {

clearSortingState();

fireTableChanged(e);

return;

}

// If the table structure has changed, cancel the sorting; the

// sorting columns may have been either moved or deleted from

// the model.

if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {

cancelSorting();

fireTableChanged(e);

return;

}

// We can map a cell event through to the view without widening

// when the following conditions apply:

//

// a) all the changes are on one row (e.getFirstRow() == e.getLastRow()) and,

// b) all the changes are in one column (column != TableModelEvent.ALL_COLUMNS) and,

// c) we are not sorting on that column (getSortingStatus(column) == NOT_SORTED) and,

// d) a reverse lookup will not trigger a sort (modelToView != null)

//

// Note: INSERT and DELETE events fail this test as they have column == ALL_COLUMNS.

//

// The last check, for (modelToView != null) is to see if modelToView

// is already allocated. If we don't do this check; sorting can become

// a performance bottleneck for applications where cells

// change rapidly in different parts of the table. If cells

// change alternately in the sorting column and then outside of

// it this class can end up re-sorting on alternate cell updates -

// which can be a performance problem for large tables. The last

// clause avoids this problem.

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;

}

// Something has happened to the data that may have invalidated the row order.

clearSortingState();

fireTableDataChanged();

return;

}

}

private class MouseHandler extends MouseAdapter {

public void mouseClicked(MouseEvent e) {

JTableHeader h = (JTableHeader) e.getSource();

TableColumnModel columnModel = h.getColumnModel();

int viewColumn = columnModel.getColumnIndexAtX(e.getX());

int column = columnModel.getColumn(viewColumn).getModelIndex();

if (column != -1) {

int status = getSortingStatus(column);

if (!e.isControlDown()) {

cancelSorting();

}

// Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or

// {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is pressed.

status = status + (e.isShiftDown() ? -1 : 1);

status = (status + 4) % 3 - 1; // signed mod, returning {-1, 0, 1}

setSortingStatus(column, status);

}

}

}

private static class Arrow implements Icon {

private boolean descending;

private int size;

private int priority;

public Arrow(boolean descending, int size, int priority) {

this.descending = descending;

this.size = size;

this.priority = priority;

}

public void paintIcon(Component c, Graphics g, int x, int y) {

Color color = c == null ? Color.GRAY : c.getBackground();

// In a compound sort, make each succesive triangle 20%

// smaller than the previous one.

int dx = (int)(size/2*Math.pow(0.8, priority));

int dy = descending ? dx : -dx;

// Align icon (roughly) with font baseline.

y = y + 5*size/6 + (descending ? -dy : 0);

int shift = descending ? 1 : -1;

g.translate(x, y);

// Right diagonal.

g.setColor(color.darker());

g.drawLine(dx / 2, dy, 0, 0);

g.drawLine(dx / 2, dy + shift, 0, shift);

// Left diagonal.

g.setColor(color.brighter());

g.drawLine(dx / 2, dy, dx, 0);

g.drawLine(dx / 2, dy + shift, dx, shift);

// Horizontal line.

if (descending) {

g.setColor(color.darker().darker());

} else {

g.setColor(color.brighter().brighter());

}

g.drawLine(dx, 0, 0, 0);

g.setColor(color);

g.translate(-x, -y);

}

public int getIconWidth() {

return size;

}

public int getIconHeight() {

return size;

}

}

private class SortableHeaderRenderer implements TableCellRenderer {

private TableCellRenderer tableCellRenderer;

public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) {

this.tableCellRenderer = tableCellRenderer;

}

public Component getTableCellRendererComponent(JTable table,

Object value,

boolean isSelected,

boolean hasFocus,

int row,

int column) {

Component c = tableCellRenderer.getTableCellRendererComponent(table,

value, isSelected, hasFocus, row, column);

if (c instanceof JLabel) {

JLabel l = (JLabel) c;

l.setHorizontalTextPosition(JLabel.LEFT);

int modelColumn = table.convertColumnIndexToModel(column);

l.setIcon(getHeaderRendererIcon(modelColumn, l.getFont().getSize()));

}

return c;

}

}

private static class Directive {

private int column;

private int direction;

public Directive(int column, int direction) {

this.column = column;

this.direction = direction;

}

}

}

java jtable 排序_解决JTable排序问题的方法详解相关推荐

  1. java调用javascript函数_[Java教程]JavaScript函数的4种调用方法详解

    [Java教程]JavaScript函数的4种调用方法详解 0 2016-08-09 00:00:12 在JavaScript中,函数是一等公民,函数在JavaScript中是一个数据类型,而非像C# ...

  2. java 三种将list转换为map的方法详解

    这篇文章主要介绍了java 三种将list转换为map的方法详解的相关资料,需要的朋友可以参考下 java 三种将list转换为map的方法详解 在本文中,介绍三种将list转换为map的方法: 1) ...

  3. Java基础提升篇:equals()与hashCode()方法详解

    概述 java.lang.Object类中有两个非常重要的方法: public boolean equals(Object obj) public int hashCode() Object类是类继承 ...

  4. 高斯消元法java语言设计_高斯消元法(Gauss Elimination)【超详解模板】

    高斯消元法,是线性代数中的一个算法,可用来求解线性方程组,并可以求出矩阵的秩,以及求出可逆方阵的逆矩阵. 高斯消元法的原理是: 若用初等行变换将增广矩阵 化为 ,则AX = B与CX = D是同解方程 ...

  5. java不规则算法_分布式id生成算法 snowflake 详解

    背景 在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识.如在支付流水号.订单号等,随者业务数据日渐增长,对数据分库分表后需要有一个唯一ID来标识一条数据或消息,数据库的自增ID显然不能满足需 ...

  6. java 双分派_双分派 和 访问者模式详解 | 学步园

    为什么 网上的人都说 java 只支持 单分派不支持双分派? 这段代码摘子某书[code=Java] public class Dispatch{ static class QQ{} static c ...

  7. mysql可重复读和间隙锁_解决MySQL可重复读——详解间隙锁

    间隙锁(Gap Lock)是Innodb在可重复读提交下为了解决幻读问题时引入的锁机制,(下面的所有案例没有特意强调都使用可重复读隔离级别)幻读的问题存在是因为新增或者更新操作,这时如果进行范围查询的 ...

  8. java 静态方法顺序_静态方法的加载顺序详解

    Java 静态代码块 静态方法区别 一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序来调 ...

  9. java+决策树结构_机器学习——决策树,DecisionTreeClassifier参数详解,决策树可视化查看树结构...

    释放双眼,带上耳机,听听看~! 0.决策树 决策树是一种树型结构,其中每个内部节结点表示在一个属性上的测试,每一个分支代表一个测试输出,每个叶结点代表一种类别. 决策树学习是以实例为基础的归纳学习 决 ...

最新文章

  1. 逼学生作弊的AI阅卷老师
  2. 伪共享(False Sharing)
  3. 牛客网(剑指offer) 第六题 旋转数组的最小数字
  4. [APIO2013]机器人(DP+SPFA最短路)
  5. HDFS查看异常:Operation category READ is not supported in state standby. Visit
  6. Bootstrap布局
  7. 多传感器融合SLAM研究和学习专栏汇总
  8. python黑帽编程视频_Python黑帽编程 3.4 跨越VLAN详解
  9. sklearn炼丹术之——Linear Models汇总
  10. 新年快乐!这是份值得收藏的2017年AI与深度学习要点大全
  11. CIA网攻中国11年,内网防护刻不容缓!
  12. android中webview的实现
  13. Ox2ac是C语言常量,计算机等级考试二级C++语言程序设计标准预测试卷二
  14. 嵌入式软件工程师面试遇到的经典题目
  15. 2.1.1 操作系统之进程的定义、特征、组成、组织
  16. JAVA自行车租借管理系统计算机毕业设计Mybatis+系统+数据库+调试部署
  17. scheduled一分钟执行一次_Spring中使用@Scheduled创建定时任务
  18. FT2004(D2000)开发实战之W25X10CL固件烧写
  19. VC++6.0 MFC显示模态对话框和非模态对话框
  20. Allegro中 设置指定的网络线宽的方法

热门文章

  1. 使用python生成信息学奥赛题目测试数据
  2. mysql空值判断怎么优化_MySQL查询语句优化的十个小技巧!
  3. 两路音频合成一路电路_CD4013构成音频线路输出双路转换器
  4. Appium 实现iPhone真机自动化-常见问题
  5. Android系统设置单双卡
  6. 在阿里“解放”鉴黄师是一种怎样的体验
  7. Vray 2.0 for 3dsmax 2008-2012中文版
  8. 手把手教你批量制作MV连播视频
  9. 关于 web 性能的思考与分享[04]——页面 SEO 优化方案
  10. 微信小程序 登录过程