Java Tutorial/Swing/JTable Sort

Материал из Java эксперт
Перейти к: навигация, поиск

A simple extension of JTable that supports the use of a SortableTableModel.

   <source lang="java">

/*

* 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 true if the data is sorted in ascending order, and
    * false otherwise.
    *
    * @return true if the data is sorted in ascending order, and
    *         false 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.
*

* 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); } }</source>

JTable Sorting in JDK6

   <source lang="java">

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);
 }

}</source>





Sorting a Column in a JTable Component

   <source lang="java">

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());
   }
 }

}</source>





Sorting and Filtering Tables

   <source lang="java">

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);
 }

}</source>





Sorting JTable Elements

   <source lang="java">

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);
 }

}</source>





Sorting the Rows in a JTable Component Based on a Column

   <source lang="java">

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());
   }
 }

}</source>





TableRowSorter with column class

   <source lang="java">

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();
 }

}</source>





TableRowSorter without column class

   <source lang="java">

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();
 }

}</source>





Using RowSorter to sort a JTable

   <source lang="java">

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);
 }

}</source>