Java Tutorial/Swing/JTable Sort — различия между версиями
Admin (обсуждение | вклад) м (1 версия) |
|
(нет различий)
|
Версия 17:44, 31 мая 2010
Содержание
- 1 A simple extension of JTable that supports the use of a SortableTableModel.
- 2 JTable Sorting in JDK6
- 3 Sorting a Column in a JTable Component
- 4 Sorting and Filtering Tables
- 5 Sorting JTable Elements
- 6 Sorting the Rows in a JTable Component Based on a Column
- 7 TableRowSorter with column class
- 8 TableRowSorter without column class
- 9 Using RowSorter to sort a JTable
A simple extension of JTable that supports the use of a SortableTableModel.
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------------
* SortableTable.java
* ------------------
* (C) Copyright 2000-2004, by Object Refinery Limited.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: SortableTable.java,v 1.5 2005/11/16 15:58:41 taqua Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
* 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
*
*/
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
/**
* A simple extension of JTable that supports the use of a SortableTableModel.
*
* @author David Gilbert
*/
public class SortableTable extends JTable {
/** A listener for sorting. */
private SortableTableHeaderListener headerListener;
/**
* Standard constructor - builds a table for the specified model.
*
* @param model the data.
*/
public SortableTable(final SortableTableModel model) {
super(model);
final SortButtonRenderer renderer = new SortButtonRenderer();
final TableColumnModel cm = getColumnModel();
for (int i = 0; i < cm.getColumnCount(); i++) {
cm.getColumn(i).setHeaderRenderer(renderer);
}
final JTableHeader header = getTableHeader();
this.headerListener = new SortableTableHeaderListener(model, renderer);
header.addMouseListener(this.headerListener);
header.addMouseMotionListener(this.headerListener);
model.sortByColumn(0, true);
}
/**
* Changes the model for the table. Takes care of updating the header listener at the
* same time.
*
* @param model the table model.
*
*/
public void setSortableModel(final SortableTableModel model) {
super.setModel(model);
this.headerListener.setTableModel(model);
final SortButtonRenderer renderer = new SortButtonRenderer();
final TableColumnModel cm = getColumnModel();
for (int i = 0; i < cm.getColumnCount(); i++) {
cm.getColumn(i).setHeaderRenderer(renderer);
}
model.sortByColumn(0, true);
}
}
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* --------------------------------
* SortableTableHeaderListener.java
* --------------------------------
* (C) Copyright 2000-2004, by Nabuo Tamemasa and Contributors.
*
* Original Author: Nabuo Tamemasa;
* Contributor(s): David Gilbert (for Object Refinery Limited);
*
* $Id: SortableTableHeaderListener.java,v 1.5 2007/11/02 17:50:36 taqua Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
* 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
*
*/
/**
* Captures mouse clicks on a table header, with the intention of triggering a sort. Adapted from
* code by Nabuo Tamemasa posted on http://www.codeguru.ru.
*
* @author Nabuo Tamemasa
*/
class SortableTableHeaderListener implements MouseListener, MouseMotionListener {
/** A reference to the table model. */
private SortableTableModel model;
/** The header renderer. */
private SortButtonRenderer renderer;
/** The index of the column that is sorted - used to determine the state of the renderer. */
private int sortColumnIndex;
/**
* Standard constructor.
*
* @param model the model.
* @param renderer the renderer.
*/
public SortableTableHeaderListener(final SortableTableModel model,
final SortButtonRenderer renderer) {
this.model = model;
this.renderer = renderer;
}
/**
* Sets the table model for the listener.
*
* @param model the model.
*/
public void setTableModel(final SortableTableModel model) {
this.model = model;
}
/**
* Handle a mouse press event - if the user is NOT resizing a column and NOT dragging a column
* then give visual feedback that the column header has been pressed.
*
* @param e the mouse event.
*/
public void mousePressed(final MouseEvent e) {
final JTableHeader header = (JTableHeader) e.getComponent();
if (header.getResizingColumn() == null) { // resizing takes precedence over sorting
if (header.getDraggedDistance() < 1) { // dragging also takes precedence over sorting
final int columnIndex = header.columnAtPoint(e.getPoint());
final int modelColumnIndex
= header.getTable().convertColumnIndexToModel(columnIndex);
if (this.model.isSortable(modelColumnIndex)) {
this.sortColumnIndex = header.getTable().convertColumnIndexToModel(columnIndex);
this.renderer.setPressedColumn(this.sortColumnIndex);
header.repaint();
if (header.getTable().isEditing()) {
header.getTable().getCellEditor().stopCellEditing();
}
}
else {
this.sortColumnIndex = -1;
}
}
}
}
/**
* If the user is dragging or resizing, then we clear the sort column.
*
* @param e the mouse event.
*/
public void mouseDragged(final MouseEvent e) {
final JTableHeader header = (JTableHeader) e.getComponent();
if ((header.getDraggedDistance() > 0) || (header.getResizingColumn() != null)) {
this.renderer.setPressedColumn(-1);
this.sortColumnIndex = -1;
}
}
/**
* This event is ignored (not required).
*
* @param e the mouse event.
*/
public void mouseEntered(final MouseEvent e) {
// not required
}
/**
* This event is ignored (not required).
*
* @param e the mouse event.
*/
public void mouseClicked(final MouseEvent e) {
// not required
}
/**
* This event is ignored (not required).
*
* @param e the mouse event.
*/
public void mouseMoved(final MouseEvent e) {
// not required
}
/**
* This event is ignored (not required).
*
* @param e the mouse event.
*/
public void mouseExited(final MouseEvent e) {
// not required
}
/**
* When the user releases the mouse button, we attempt to sort the table.
*
* @param e the mouse event.
*/
public void mouseReleased(final MouseEvent e) {
final JTableHeader header = (JTableHeader) e.getComponent();
if (header.getResizingColumn() == null) { // resizing takes precedence over sorting
if (this.sortColumnIndex != -1) {
final SortableTableModel model = (SortableTableModel) header.getTable().getModel();
final boolean ascending = !model.isAscending();
model.setAscending(ascending);
model.sortByColumn(this.sortColumnIndex, ascending);
this.renderer.setPressedColumn(-1); // clear
header.repaint();
}
}
}
}
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* -----------------------
* SortableTableModel.java
* -----------------------
* (C) Copyright 2000-2005, by Object Refinery Limited;
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: SortableTableModel.java,v 1.6 2008/09/10 09:26:11 mungady Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.* (DG);
* 20-Nov-2001 : Made constructor protected (DG);
* 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
*
*/
/**
* The base class for a sortable table model.
*
* @author David Gilbert
*/
abstract class SortableTableModel extends AbstractTableModel {
/** The column on which the data is sorted (-1 for no sorting). */
private int sortingColumn;
/** Indicates ascending (true) or descending (false) order. */
private boolean ascending;
/**
* Constructs a sortable table model.
*/
public SortableTableModel() {
this.sortingColumn = -1;
this.ascending = true;
}
/**
* Returns the index of the sorting column, or -1 if the data is not sorted
* on any column.
*
* @return the column used for sorting.
*/
public int getSortingColumn() {
return this.sortingColumn;
}
/**
* Returns <code>true</code> if the data is sorted in ascending order, and
* <code>false</code> otherwise.
*
* @return <code>true</code> if the data is sorted in ascending order, and
* <code>false</code> otherwise.
*/
public boolean isAscending() {
return this.ascending;
}
/**
* Sets the flag that determines whether the sort order is ascending or
* descending.
*
* @param flag the flag.
*/
public void setAscending(final boolean flag) {
this.ascending = flag;
}
/**
* Sorts the table.
*
* @param column the column to sort on (zero-based index).
* @param ascending a flag to indicate ascending order or descending order.
*/
public void sortByColumn(final int column, final boolean ascending) {
if (isSortable(column)) {
this.sortingColumn = column;
}
}
/**
* Returns a flag indicating whether or not a column is sortable.
*
* @param column the column (zero-based index).
*
* @return boolean.
*/
public boolean isSortable(final int column) {
return false;
}
}
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* -----------------------
* SortButtonRenderer.java
* -----------------------
* (C) Copyright 2000-2004, by Nobuo Tamemasa and Contributors.
*
* Original Author: Nobuo Tamemasa;
* Contributor(s): David Gilbert (for Object Refinery Limited);
* Gareth Davis;
*
* $Id: SortButtonRenderer.java,v 1.7 2008/09/10 09:26:11 mungady Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.* (DG);
* 26-Jun-2002 : Removed unnecessary import (DG);
* 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
*
*/
/**
* A table cell renderer for table headings - uses one of three JButton instances to indicate the
* sort order for the table column.
* <P>
* This class (and also BevelArrowIcon) is adapted from original code by Nobuo Tamemasa (version
* 1.0, 26-Feb-1999) posted on www.codeguru.ru.
*
* @author David Gilbert
*/
class SortButtonRenderer implements TableCellRenderer {
/**
* Useful constant indicating NO sorting.
*/
public static final int NONE = 0;
/**
* Useful constant indicating ASCENDING (that is, arrow pointing down) sorting in the table.
*/
public static final int DOWN = 1;
/**
* Useful constant indicating DESCENDING (that is, arrow pointing up) sorting in the table.
*/
public static final int UP = 2;
/**
* The current pressed column (-1 for no column).
*/
private int pressedColumn = -1;
/**
* The three buttons that are used to render the table header cells.
*/
private JButton normalButton;
/**
* The three buttons that are used to render the table header cells.
*/
private JButton ascendingButton;
/**
* The three buttons that are used to render the table header cells.
*/
private JButton descendingButton;
/**
* Used to allow the class to work out whether to use the buttuns
* or labels. Labels are required when using the aqua look and feel cos the
* buttons won"t fit.
*/
private boolean useLabels;
/**
* The normal label (only used with MacOSX).
*/
private JLabel normalLabel;
/**
* The ascending label (only used with MacOSX).
*/
private JLabel ascendingLabel;
/**
* The descending label (only used with MacOSX).
*/
private JLabel descendingLabel;
/**
* Creates a new button renderer.
*/
public SortButtonRenderer() {
this.pressedColumn = -1;
this.useLabels = UIManager.getLookAndFeel().getID().equals("Aqua");
final Border border = UIManager.getBorder("TableHeader.cellBorder");
if (this.useLabels) {
this.normalLabel = new JLabel();
this.normalLabel.setHorizontalAlignment(SwingConstants.LEADING);
this.ascendingLabel = new JLabel();
this.ascendingLabel.setHorizontalAlignment(SwingConstants.LEADING);
this.ascendingLabel.setHorizontalTextPosition(SwingConstants.LEFT);
this.ascendingLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
this.descendingLabel = new JLabel();
this.descendingLabel.setHorizontalAlignment(SwingConstants.LEADING);
this.descendingLabel.setHorizontalTextPosition(SwingConstants.LEFT);
this.descendingLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
this.normalLabel.setBorder(border);
this.ascendingLabel.setBorder(border);
this.descendingLabel.setBorder(border);
}
else {
this.normalButton = new JButton();
this.normalButton.setMargin(new Insets(0, 0, 0, 0));
this.normalButton.setHorizontalAlignment(SwingConstants.LEADING);
this.ascendingButton = new JButton();
this.ascendingButton.setMargin(new Insets(0, 0, 0, 0));
this.ascendingButton.setHorizontalAlignment(SwingConstants.LEADING);
this.ascendingButton.setHorizontalTextPosition(SwingConstants.LEFT);
this.ascendingButton.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
this.ascendingButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, true));
this.descendingButton = new JButton();
this.descendingButton.setMargin(new Insets(0, 0, 0, 0));
this.descendingButton.setHorizontalAlignment(SwingConstants.LEADING);
this.descendingButton.setHorizontalTextPosition(SwingConstants.LEFT);
this.descendingButton.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
this.descendingButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, true));
this.normalButton.setBorder(border);
this.ascendingButton.setBorder(border);
this.descendingButton.setBorder(border);
}
}
/**
* Returns the renderer component.
*
* @param table the table.
* @param value the value.
* @param isSelected selected?
* @param hasFocus focussed?
* @param row the row.
* @param column the column.
* @return the renderer.
*/
public Component getTableCellRendererComponent(final JTable table,
final Object value,
final boolean isSelected,
final boolean hasFocus,
final int row, final int column) {
if (table == null) {
throw new NullPointerException("Table must not be null.");
}
final JComponent component;
final SortableTableModel model = (SortableTableModel) table.getModel();
final int cc = table.convertColumnIndexToModel(column);
final boolean isSorting = (model.getSortingColumn() == cc);
final boolean isAscending = model.isAscending();
final JTableHeader header = table.getTableHeader();
final boolean isPressed = (cc == this.pressedColumn);
if (this.useLabels) {
final JLabel label = getRendererLabel(isSorting, isAscending);
label.setText((value == null) ? "" : value.toString());
component = label;
}
else {
final JButton button = getRendererButton(isSorting, isAscending);
button.setText((value == null) ? "" : value.toString());
button.getModel().setPressed(isPressed);
button.getModel().setArmed(isPressed);
component = button;
}
if (header != null) {
component.setForeground(header.getForeground());
component.setBackground(header.getBackground());
component.setFont(header.getFont());
}
return component;
}
/**
* Returns the correct button component.
*
* @param isSorting whether the render component represents the sort column.
* @param isAscending whether the model is ascending.
* @return either the ascending, descending or normal button.
*/
private JButton getRendererButton(final boolean isSorting, final boolean isAscending) {
if (isSorting) {
if (isAscending) {
return this.ascendingButton;
}
else {
return this.descendingButton;
}
}
else {
return this.normalButton;
}
}
/**
* Returns the correct label component.
*
* @param isSorting whether the render component represents the sort column.
* @param isAscending whether the model is ascending.
* @return either the ascending, descending or normal label.
*/
private JLabel getRendererLabel(final boolean isSorting, final boolean isAscending) {
if (isSorting) {
if (isAscending) {
return this.ascendingLabel;
}
else {
return this.descendingLabel;
}
}
else {
return this.normalLabel;
}
}
/**
* Sets the pressed column.
*
* @param column the column.
*/
public void setPressedColumn(final int column) {
this.pressedColumn = column;
}
}
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* -------------------
* BevelArrowIcon.java
* -------------------
* (C) Copyright 2000-2004, by Nobuo Tamemasa and Contributors.
*
* Original Author: Nobuo Tamemasa;
* Contributor(s): David Gilbert (for Object Refinery Limited);
*
* $Id: BevelArrowIcon.java,v 1.5 2007/11/02 17:50:36 taqua Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
* 13-Oct-2002 : Fixed errors reported by Checkstyle (DG);
*
*/
/**
* An arrow icon that can point up or down (usually used to indicate the sort direction in a table).
* <P>
* This class (and also SortButtonRenderer) is based on original code by Nobuo Tamemasa (version
* 1.0, 26-Feb-1999) posted on www.codeguru.ru.
*
* @author Nobuo Tamemasa
*/
class BevelArrowIcon implements Icon {
/** Constant indicating that the arrow is pointing up. */
public static final int UP = 0;
/** Constant indicating that the arrow is pointing down. */
public static final int DOWN = 1;
/** The default arrow size. */
private static final int DEFAULT_SIZE = 11;
/** Edge color 1. */
private Color edge1;
/** Edge color 2. */
private Color edge2;
/** The fill color for the arrow icon. */
private Color fill;
/** The size of the icon. */
private int size;
/** The direction that the arrow is pointing (UP or DOWN). */
private int direction;
/**
* Standard constructor - builds an icon with the specified attributes.
*
* @param direction .
* @param isRaisedView .
* @param isPressedView .
*/
public BevelArrowIcon(final int direction,
final boolean isRaisedView,
final boolean isPressedView) {
if (isRaisedView) {
if (isPressedView) {
init(UIManager.getColor("controlLtHighlight"),
UIManager.getColor("controlDkShadow"),
UIManager.getColor("controlShadow"),
DEFAULT_SIZE, direction);
}
else {
init(UIManager.getColor("controlHighlight"),
UIManager.getColor("controlShadow"),
UIManager.getColor("control"),
DEFAULT_SIZE, direction);
}
}
else {
if (isPressedView) {
init(UIManager.getColor("controlDkShadow"),
UIManager.getColor("controlLtHighlight"),
UIManager.getColor("controlShadow"),
DEFAULT_SIZE, direction);
}
else {
init(UIManager.getColor("controlShadow"),
UIManager.getColor("controlHighlight"),
UIManager.getColor("control"),
DEFAULT_SIZE, direction);
}
}
}
/**
* Standard constructor - builds an icon with the specified attributes.
*
* @param edge1 the color of edge1.
* @param edge2 the color of edge2.
* @param fill the fill color.
* @param size the size of the arrow icon.
* @param direction the direction that the arrow points.
*/
public BevelArrowIcon(final Color edge1,
final Color edge2,
final Color fill,
final int size,
final int direction) {
init(edge1, edge2, fill, size, direction);
}
/**
* Paints the icon at the specified position. Supports the Icon interface.
*
* @param c .
* @param g .
* @param x .
* @param y .
*/
public void paintIcon(final Component c,
final Graphics g,
final int x,
final int y) {
switch (this.direction) {
case DOWN: drawDownArrow(g, x, y); break;
case UP: drawUpArrow(g, x, y); break;
}
}
/**
* Returns the width of the icon. Supports the Icon interface.
*
* @return the icon width.
*/
public int getIconWidth() {
return this.size;
}
/**
* Returns the height of the icon. Supports the Icon interface.
* @return the icon height.
*/
public int getIconHeight() {
return this.size;
}
/**
* Initialises the attributes of the arrow icon.
*
* @param edge1 the color of edge1.
* @param edge2 the color of edge2.
* @param fill the fill color.
* @param size the size of the arrow icon.
* @param direction the direction that the arrow points.
*/
private void init(final Color edge1,
final Color edge2,
final Color fill,
final int size,
final int direction) {
this.edge1 = edge1;
this.edge2 = edge2;
this.fill = fill;
this.size = size;
this.direction = direction;
}
/**
* Draws the arrow pointing down.
*
* @param g the graphics device.
* @param xo ??
* @param yo ??
*/
private void drawDownArrow(final Graphics g, final int xo, final int yo) {
g.setColor(this.edge1);
g.drawLine(xo, yo, xo + this.size - 1, yo);
g.drawLine(xo, yo + 1, xo + this.size - 3, yo + 1);
g.setColor(this.edge2);
g.drawLine(xo + this.size - 2, yo + 1, xo + this.size - 1, yo + 1);
int x = xo + 1;
int y = yo + 2;
int dx = this.size - 6;
while (y + 1 < yo + this.size) {
g.setColor(this.edge1);
g.drawLine(x, y, x + 1, y);
g.drawLine(x, y + 1, x + 1, y + 1);
if (0 < dx) {
g.setColor(this.fill);
g.drawLine(x + 2, y, x + 1 + dx, y);
g.drawLine(x + 2, y + 1, x + 1 + dx, y + 1);
}
g.setColor(this.edge2);
g.drawLine(x + dx + 2, y, x + dx + 3, y);
g.drawLine(x + dx + 2, y + 1, x + dx + 3, y + 1);
x += 1;
y += 2;
dx -= 2;
}
g.setColor(this.edge1);
g.drawLine(
xo + (this.size / 2), yo + this.size - 1, xo + (this.size / 2), yo + this.size - 1
);
}
/**
* Draws the arrow pointing up.
*
* @param g the graphics device.
* @param xo ??
* @param yo ??
*/
private void drawUpArrow(final Graphics g, final int xo, final int yo) {
g.setColor(this.edge1);
int x = xo + (this.size / 2);
g.drawLine(x, yo, x, yo);
x--;
int y = yo + 1;
int dx = 0;
while (y + 3 < yo + this.size) {
g.setColor(this.edge1);
g.drawLine(x, y, x + 1, y);
g.drawLine(x, y + 1, x + 1, y + 1);
if (0 < dx) {
g.setColor(this.fill);
g.drawLine(x + 2, y, x + 1 + dx, y);
g.drawLine(x + 2, y + 1, x + 1 + dx, y + 1);
}
g.setColor(this.edge2);
g.drawLine(x + dx + 2, y, x + dx + 3, y);
g.drawLine(x + dx + 2, y + 1, x + dx + 3, y + 1);
x -= 1;
y += 2;
dx += 2;
}
g.setColor(this.edge1);
g.drawLine(xo, yo + this.size - 3, xo + 1, yo + this.size - 3);
g.setColor(this.edge2);
g.drawLine(xo + 2, yo + this.size - 2, xo + this.size - 1, yo + this.size - 2);
g.drawLine(xo, yo + this.size - 1, xo + this.size, yo + this.size - 1);
}
}
JTable Sorting in JDK6
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class JTableSortDemo {
public static void main(String[] args) {
Object[][] data = { { "A", 5 }, { "B", 2 }, { "C", 4 }, { "D", 8 } };
String columnNames[] = { "Item", "Value" };
TableModel model = new DefaultTableModel(data, columnNames) {
public Class<?> getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
JTable table = new JTable(model);
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
JScrollPane scrollPane = new JScrollPane(table);
JFrame frame = new JFrame("Sorting Table");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane);
frame.setSize(300, 200);
frame.setVisible(true);
}
}
Sorting a Column in a JTable Component
import java.util.Arrays;
import java.util.ruparator;
import java.util.Vector;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
table.setAutoCreateColumnsFromModel(false);
boolean ascending = false;
Vector data = model.getDataVector();
Object[] colData = new Object[model.getRowCount()];
for (int i = 0; i < colData.length; i++) {
colData[i] = ((Vector) data.get(i)).get(0);
}
Arrays.sort(colData, new ColumnSorter());
for (int i = 0; i < colData.length; i++) {
((Vector) data.get(i)).set(0, colData[i]);
}
model.fireTableStructureChanged();
}
}
class ColumnSorter implements Comparator {
ColumnSorter() {
}
public int compare(Object a, Object b) {
if (a instanceof String && ((String) a).length() == 0) {
a = null;
}
if (b instanceof String && ((String) b).length() == 0) {
b = null;
}
if (a == null && b == null) {
return 0;
} else if (a == null) {
return 1;
} else if (b == null) {
return -1;
} else if (a instanceof Comparable) {
return ((Comparable) a).rupareTo(b);
} else {
return a.toString().rupareTo(b.toString());
}
}
}
Sorting and Filtering Tables
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class Main {
public static void main(String args[]) {
JFrame frame = new JFrame("Sorting JTable");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Object rows[][] = { { "A", "A", 1 }, { "E", "E", 4 }, { "Y", "Y", 3 } };
String columns[] = { "Symbol", "Name", "Price" };
TableModel model = new DefaultTableModel(rows, columns) {
public Class getColumnClass(int column) {
Class returnValue;
if ((column >= 0) && (column < getColumnCount())) {
returnValue = getValueAt(0, column).getClass();
} else {
returnValue = Object.class;
}
return returnValue;
}
};
JTable table = new JTable(model);
RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
JScrollPane pane = new JScrollPane(table);
frame.add(pane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
Sorting JTable Elements
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
public class ListProperties {
static class CustomTableModel extends AbstractTableModel {
Vector keys = new Vector();
Vector values = new Vector();
private static final String columnNames[] = { "Property String", "Value" };
public int getColumnCount() {
return columnNames.length;
}
public String getColumnName(int column) {
return columnNames[column];
}
public int getRowCount() {
return keys.size();
}
public Object getValueAt(int row, int column) {
Object returnValue = null;
if (column == 0) {
returnValue = keys.elementAt(row);
} else if (column == 1) {
returnValue = values.elementAt(row);
}
return returnValue;
}
public synchronized void uiDefaultsUpdate(UIDefaults defaults) {
Enumeration newKeys = defaults.keys();
keys.removeAllElements();
while (newKeys.hasMoreElements()) {
keys.addElement(newKeys.nextElement());
}
Enumeration newValues = defaults.elements();
values.removeAllElements();
while (newValues.hasMoreElements()) {
values.addElement(newValues.nextElement());
}
fireTableDataChanged();
}
}
public static void main(String args[]) {
final JFrame frame = new JFrame("List Properties");
final CustomTableModel model = new CustomTableModel();
model.uiDefaultsUpdate(UIManager.getDefaults());
TableSorter sorter = new TableSorter(model);
JTable table = new JTable(sorter);
TableHeaderSorter.install(sorter, table);
table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
Container content = frame.getContentPane();
JScrollPane scrollPane = new JScrollPane(table);
content.add(scrollPane, BorderLayout.CENTER);
frame.setSize(400, 400);
frame.setVisible(true);
}
}
class TableSorter extends TableMap implements TableModelListener {
int indexes[] = new int[0];
Vector sortingColumns = new Vector();
boolean ascending = true;
public TableSorter() {
}
public TableSorter(TableModel model) {
setModel(model);
}
public void setModel(TableModel model) {
super.setModel(model);
reallocateIndexes();
sortByColumn(0);
fireTableDataChanged();
}
public int compareRowsByColumn(int row1, int row2, int column) {
Class type = model.getColumnClass(column);
TableModel data = model;
// Check for nulls
Object o1 = data.getValueAt(row1, column);
Object o2 = data.getValueAt(row2, column);
// If both values are null return 0
if (o1 == null && o2 == null) {
return 0;
} else if (o1 == null) { // Define null less than everything.
return -1;
} else if (o2 == null) {
return 1;
}
if (type.getSuperclass() == Number.class) {
Number n1 = (Number) data.getValueAt(row1, column);
double d1 = n1.doubleValue();
Number n2 = (Number) data.getValueAt(row2, column);
double d2 = n2.doubleValue();
if (d1 < d2)
return -1;
else if (d1 > d2)
return 1;
else
return 0;
} else if (type == String.class) {
String s1 = (String) data.getValueAt(row1, column);
String s2 = (String) data.getValueAt(row2, column);
int result = s1.rupareTo(s2);
if (result < 0)
return -1;
else if (result > 0)
return 1;
else
return 0;
} else if (type == java.util.Date.class) {
Date d1 = (Date) data.getValueAt(row1, column);
long n1 = d1.getTime();
Date d2 = (Date) data.getValueAt(row2, column);
long n2 = d2.getTime();
if (n1 < n2)
return -1;
else if (n1 > n2)
return 1;
else
return 0;
} else if (type == Boolean.class) {
Boolean bool1 = (Boolean) data.getValueAt(row1, column);
boolean b1 = bool1.booleanValue();
Boolean bool2 = (Boolean) data.getValueAt(row2, column);
boolean b2 = bool2.booleanValue();
if (b1 == b2)
return 0;
else if (b1) // Define false < true
return 1;
else
return -1;
} else {
Object v1 = data.getValueAt(row1, column);
String s1 = v1.toString();
Object v2 = data.getValueAt(row2, column);
String s2 = v2.toString();
int result = s1.rupareTo(s2);
if (result < 0)
return -1;
else if (result > 0)
return 1;
else
return 0;
}
}
public int compare(int row1, int row2) {
for (int level = 0, n = sortingColumns.size(); level < n; level++) {
Integer column = (Integer) sortingColumns.elementAt(level);
int result = compareRowsByColumn(row1, row2, column.intValue());
if (result != 0) {
return (ascending ? result : -result);
}
}
return 0;
}
public void reallocateIndexes() {
int rowCount = model.getRowCount();
indexes = new int[rowCount];
for (int row = 0; row < rowCount; row++) {
indexes[row] = row;
}
}
public void tableChanged(TableModelEvent tableModelEvent) {
super.tableChanged(tableModelEvent);
reallocateIndexes();
sortByColumn(0);
fireTableStructureChanged();
}
public void checkModel() {
if (indexes.length != model.getRowCount()) {
System.err.println("Sorter not informed of a change in model.");
}
}
public void sort() {
checkModel();
shuttlesort((int[]) indexes.clone(), indexes, 0, indexes.length);
fireTableDataChanged();
}
public void shuttlesort(int from[], int to[], int low, int high) {
if (high - low < 2) {
return;
}
int middle = (low + high) / 2;
shuttlesort(to, from, low, middle);
shuttlesort(to, from, middle, high);
int p = low;
int q = middle;
for (int i = low; i < high; i++) {
if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) {
to[i] = from[p++];
} else {
to[i] = from[q++];
}
}
}
private void swap(int first, int second) {
int temp = indexes[first];
indexes[first] = indexes[second];
indexes[second] = temp;
}
public Object getValueAt(int row, int column) {
checkModel();
return model.getValueAt(indexes[row], column);
}
public void setValueAt(Object aValue, int row, int column) {
checkModel();
model.setValueAt(aValue, indexes[row], column);
}
public void sortByColumn(int column) {
sortByColumn(column, true);
}
public void sortByColumn(int column, boolean ascending) {
this.ascending = ascending;
sortingColumns.removeAllElements();
sortingColumns.addElement(new Integer(column));
sort();
super.tableChanged(new TableModelEvent(this));
}
}
class TableHeaderSorter extends MouseAdapter {
private TableSorter sorter;
private JTable table;
private TableHeaderSorter() {
}
public static void install(TableSorter sorter, JTable table) {
TableHeaderSorter tableHeaderSorter = new TableHeaderSorter();
tableHeaderSorter.sorter = sorter;
tableHeaderSorter.table = table;
JTableHeader tableHeader = table.getTableHeader();
tableHeader.addMouseListener(tableHeaderSorter);
}
public void mouseClicked(MouseEvent mouseEvent) {
TableColumnModel columnModel = table.getColumnModel();
int viewColumn = columnModel.getColumnIndexAtX(mouseEvent.getX());
int column = table.convertColumnIndexToModel(viewColumn);
if (mouseEvent.getClickCount() == 1 && column != -1) {
System.out.println("Sorting ...");
int shiftPressed = (mouseEvent.getModifiers() & InputEvent.SHIFT_MASK);
boolean ascending = (shiftPressed == 0);
sorter.sortByColumn(column, ascending);
}
}
}
class TableMap extends AbstractTableModel implements TableModelListener {
TableModel model;
public TableModel getModel() {
return model;
}
public void setModel(TableModel model) {
if (this.model != null) {
this.model.removeTableModelListener(this);
}
this.model = model;
if (this.model != null) {
this.model.addTableModelListener(this);
}
}
public Class getColumnClass(int column) {
return model.getColumnClass(column);
}
public int getColumnCount() {
return ((model == null) ? 0 : model.getColumnCount());
}
public String getColumnName(int column) {
return model.getColumnName(column);
}
public int getRowCount() {
return ((model == null) ? 0 : model.getRowCount());
}
public Object getValueAt(int row, int column) {
return model.getValueAt(row, column);
}
public void setValueAt(Object value, int row, int column) {
model.setValueAt(value, row, column);
}
public boolean isCellEditable(int row, int column) {
return model.isCellEditable(row, column);
}
public void tableChanged(TableModelEvent tableModelEvent) {
fireTableChanged(tableModelEvent);
}
}
Sorting the Rows in a JTable Component Based on a Column
import java.util.Collections;
import java.util.ruparator;
import java.util.Vector;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
table.setAutoCreateColumnsFromModel(false);
Vector data = model.getDataVector();
Collections.sort(data, new ColumnSorter(0));
model.fireTableStructureChanged();
}
}
class ColumnSorter implements Comparator {
int colIndex;
ColumnSorter(int colIndex) {
this.colIndex = colIndex;
}
public int compare(Object a, Object b) {
Vector v1 = (Vector) a;
Vector v2 = (Vector) b;
Object o1 = v1.get(colIndex);
Object o2 = v2.get(colIndex);
if (o1 instanceof String && ((String) o1).length() == 0) {
o1 = null;
}
if (o2 instanceof String && ((String) o2).length() == 0) {
o2 = null;
}
if (o1 == null && o2 == null) {
return 0;
} else if (o1 == null) {
return 1;
} else if (o2 == null) {
return -1;
} else if (o1 instanceof Comparable) {
return ((Comparable) o1).rupareTo(o2);
} else {
return o1.toString().rupareTo(o2.toString());
}
}
}
TableRowSorter with column class
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class TableRowSorterWithHeader extends JFrame {
public TableRowSorterWithHeader() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
String[] columns = { "Item", "Price" };
Object[][] rows = { { "Potatoes", 10.98 }, { "Magazine", 7.99 },
{ "Can of soup", 0.89 }, { "DVD movie", 39.99 } };
TableModel model = new DefaultTableModel(rows, columns) {
public Class getColumnClass(int column) {
if (column >= 0 && column <= getColumnCount())
return getValueAt(0, column).getClass();
else
return Object.class;
}
};
JTable table = new JTable(model);
RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
getContentPane().add(new JScrollPane(table));
setSize(200, 150);
setVisible(true);
}
public static void main(String[] args) {
new TableRowSorterWithHeader();
}
}
TableRowSorter without column class
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class TableRowSorterWithoutColumnClass extends JFrame {
public TableRowSorterWithoutColumnClass() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
String[] columns = { "Item", "Price" };
Object[][] rows = { { "P", 10.98 }, { "Magazine", 7.99 },
{ "Can of soup", 0.89 }, { "DVD movie", 39.99 } };
TableModel model = new DefaultTableModel(rows, columns);
JTable table = new JTable(model);
RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
getContentPane().add(new JScrollPane(table));
setSize(200, 150);
setVisible(true);
}
public static void main(String[] args) {
new TableRowSorterWithoutColumnClass();
}
}
Using RowSorter to sort a JTable
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class RowSorterDemo {
public static void main(String args[]) {
JFrame frame = new JFrame("Sort Table Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Object rows[][] = { { "J", 23 }, { "R", 24, }, { "E", 21, }, { "B", 27, }, { "A", 25, },
{ "S", 22, }, };
String columns[] = { "Name", "Age" };
TableModel model = new DefaultTableModel(rows, columns) {
public Class getColumnClass(int column) {
Class returnValue;
if ((column >= 0) && (column < getColumnCount())) {
returnValue = getValueAt(0, column).getClass();
} else {
returnValue = Object.class;
}
return returnValue;
}
};
JTable table = new JTable(model);
RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
JScrollPane pane = new JScrollPane(table);
frame.add(pane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}