Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4747079
Votes 12
Synopsis Add sorting ability to JTable
Category java:classes_swing
Reported Against 1.4 , tiger-beta
Release Fixed mustang(b39)
State 10-Fix Delivered, request for enhancement
Priority: 3-Medium
Related Bugs 6329506 , 6329499 , 4667991 , 6389065 , 4765361 , 4855121 , 6403371 , 4714237 , 4752713
Submit Date 13-SEP-2002
Description
This was pulled from 4267065:




It would be great if Swing included the TableSorter classes
published in the Swing Connection as part of the official
Swing release.  It would avoid a lot of code duplication since
I bet 95% of people writing JTables need to be able to sort
them.  Furthermore, it should include icons to visually notify
the user by which column the table is currently sorted, etc.

Yes, I know it can be done on top of Swing (and that only
shows that Swing has been very well designed), but it is such
a common feature that IMO it should be a part of Swing.

Thanks in advance,

Hernan
(Review ID: 94476)
======================================================================

Another customer comments:
I just read where sorting will be restored to JTable in Tiger.
I would like to suggest that sorting by an invisible column be allowed.
We sometimes have a column in the model, that is calculated from several
of the other columns,  that is  the default sort order for the rows.
When clicking on the column header we go thru 3 states for the sort:
ascending, descending, & default column.
If the table doesn't have an invisible default sort column, then it just
has ascending & descending.

=============================================================================
  xxxxx@xxxxx   2004-01-05

Same request from a CAP member and suggested methods:

suggest this SortableTableModel class

If set SortableTableModel to a JTable
then this JTable get sorting ability.

If click a header, the whole rows of JTable are sorted 
acoording to the column which is clicked.

The attached file  FileTable.zip has 3 files :

SortableTableModel.java
  TbleModel which can sort JTable data

FileTable.java
  the example to use SortableTableMode

FileTableTest.java
  test driver which has main method for FileTable and also SortableTableModel.

------------------------------------------------------------------------------
The following is a flagment of FileTable which shows how to use SortableTableModel

class FileTable extends JTable {

   DefaultTableModel model;
   String dirName;

   FileTable( String dirName ){
      super();
      if( dirName==null ) dirName = ".";

      model = new SortableTableModel( this, columnNames, 0 );
      setModel( model ); // just set SortableTableModel

      setRowSelectionAllowed(false); // this is important
      //.......

-----------------------------------------------------------------------------
The the following is the code of SortableTableModel.java
//------------------------------ SortableTableModel.java
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class SortableTableModel extends DefaultTableModel {
  JTable table;
  JTableHeader header;
  Vector columnNames;
  int selectedHeaderColumn;
  int columnCount;
  int[] minWidth;
  TableCellRenderer[] cellRenderer;
  int clickCount = 0;

  public SortableTableModel( JTable table, String[] columnNames, int rowCount ){
    super( columnNames, rowCount );
    this.table = table;
    header = table.getTableHeader();
    header.setReorderingAllowed(false);
    header.addMouseListener( new HeaderMouseAdapter() );
    this.columnNames = DefaultTableModel.convertToVector( columnNames );
    columnCount = columnNames.length;
    minWidth = new int[ columnCount ];
    cellRenderer = new TableCellRenderer[ columnCount ];
  }

  class HeaderMouseAdapter extends MouseAdapter {
    public void mousePressed( MouseEvent e ){
      Point mousePoint = new Point( e.getX(), e.getY() );
      selectedHeaderColumn = header.columnAtPoint( mousePoint );
      DefaultTableColumnModel cmodel = (DefaultTableColumnModel)table.getColumnModel();
      backupTableColumnAttr( cmodel );

      clickCount++;
      boolean reverseOrder = false;
      if( ( clickCount %2 )==0 ) reverseOrder = true;
      sort( reverseOrder );

      restoreTableColumnAttr( cmodel );
    }
    void backupTableColumnAttr( DefaultTableColumnModel cmodel ){
      for( int i=0 ; i< columnCount ; i++ ){
        TableColumn column = cmodel.getColumn(i);
        minWidth[i] = column.getMinWidth();
        cellRenderer[i] = column.getCellRenderer();
      }
    }
    void restoreTableColumnAttr( DefaultTableColumnModel cmodel ){
      for( int i=0 ; i< columnCount ; i++ ){
        TableColumn column = cmodel.getColumn(i);
        column.setMinWidth( minWidth[i] );
        column.setCellRenderer( cellRenderer[i] );
      }
    }
  }

  void sort( boolean reverseOrder ){
    Vector vec = getDataVector();
    Object[] array = vec.toArray();
    Arrays.sort( array, new Compare( selectedHeaderColumn, reverseOrder ) );
    vec = DefaultTableModel.convertToVector( array );
    setDataVector( vec, columnNames );
  }

  class Compare implements Comparator {
    int sortKey;
    boolean reverseOrder;
    Compare( int sortKey, boolean reverseOrder ){
      this.sortKey = sortKey;
      this.reverseOrder = reverseOrder;
    }
    public int compare( Object o1, Object o2 ){
      Vector v1 = (Vector)o1;
      Vector v2 = (Vector)o2;
      Comparable s1 = (Comparable)v1.get( sortKey );
      Comparable s2 = (Comparable)v2.get( sortKey );
      int ans = s1.compareTo( s2 );
      if( reverseOrder ) ans *= -1;
      return( ans );
    }
    public boolean equals( Object obj ){
      return( false );
    }

  }
}
//------------------------------------------------------------------------------
Work Around
N/A
Evaluation
JTable now offers the ability to sort and filter at the row level.  This resulted in introducing the following API:

TableStringConverter: This is responsible for converting Object values to Strings.  As of this feature sorting is the only one that can make use of this class.  This class allows you to use a separate class that is responsible for converting the objects to string when comparing.  You do not need this to use sorting, it's only useful if you don't want to overload getValueAt to convert to Strings.

RowFilter: Adds the ability to filter out rows from the view.  Has the single method include as well as various static methods to get instances meeting certain criteria (like numbers, strings, dates...)

SortOrder: Enum of ascending/descending/unsorted

RowSorter: Object responsible for mapping coordinates between the table model and JTable.  RowSorter also has it's own listener, a List of sort orders and methods that are called when the model changes.  This class is not specific to JTable.

DefaultRowSorter: Default implementation of RowSorter.  This does not use TableModel, rather it's own Model class.  Has methods for setting Comparators per column, whether or not a column is sortable, max number of sort keys ...

TableRowSorter: TableModel specific implementation of RowSorter.  It extends DefaultRowSorter providing it's own DefaultRowSorter.Model implementation that wraps TableModel.

And finally JTable has methods for setting the RowSorter, mapping coordinates and listeners to sorter changes.

Here's what you'll do to turn on sorting:

  TableModel myModel =  createTableModel();
  JTable table = new JTable(myModel);
  table.setRowSorter(new TableRowSorter(myModel));

To handle mapping of indices you'll need to do:

  int[] selection = table.getSelectedRows();
  for (int i = 0; i < selection.length; i++) {
    selection[i] = table.convertRowIndexToModel(selection[i]);
  }


  xxxxx@xxxxx   2005-05-25 22:30:38 GMT
Comments
  
  Include a link with my name & email   

Submitted On 05-MAY-2003
qajava
Beyond sorting, please consider adding support for filterable 
JTables.


Submitted On 23-FEB-2004
Jason-Mehrens
Sorting on the model level would change all views so 
to me 
that implies it must be done in the view (the actual 
JTable).

I suggest that sorting framework would work like the 
renderer/editor via methods like these:
public void setDefaultComparator(Class clazz, 
Comparator c) //in the Table
public Comparator getDefaultComparator(Class 
colClass)  //in the table
public Comparator getComparator(int 
columnIndex) //in the column object and table
public void setComparator(int columnIndex)       //in the 
column object and table

The user selection must be maintained when a sort 
happens or it would not be very useful.
What about 
ListSelectionModel.SINGLE_INTERVAL_SELECTION 
where not all rows in a table are selected? 
Clear the selection on every sort?  Don't allow the 
mode at all?  Force a change to MULTI/SINGLE?

Automatic sorting of new rows and cells edited in the 
sorted column would be nice.  
It would have to be a property that could be 
enabled/disabled.

The ability to sort rows in contiguous selection would 
be nice in addition to sorting all the rows in the table.
Multi-column sorting using a primary, secondary,..etc 
would be a great feature too.

At any rate the JTable still rocks!

JM


Submitted On 02-FEB-2005
approach
JTable should support column sorting and column-autosize RIGHT OUT OF THE BOX, end of story.

If the Swing team hadn't been asleep at the switch for so many YEARS, these features would have been implemented long ago.

JTable definitely does not "rock".


Submitted On 21-APR-2005
joegood
Would just like to add that the sorting and filtering needs to support items being added to the model.  Not just static sorting and filtering.

Also, I am not sure that TableSorter is the best way to go about this.  We used quick sort for doing an initial sort and then binary search to sort new items.

To make a long story short don't just use TableSorter..please


Submitted On 25-APR-2005
uss_bruckner
Please, consider using Glazed Lists (http://publicobject.com/glazedlists/), or at least have a look at it! It's a sufficiently general framework for sorting and filtering tables, combos and lists. It's architecture is clean, and we use it extensively. It has been a real lifesaver, and would boost usability of tables in Swing (both from a developer and user point of view).


Submitted On 03-MAY-2005
capaccin_o@yahoo.com.cn
Beyond sorting,please consider adding support for merge cell


Submitted On 27-MAY-2005
MiguelM
While I'm happy to see sorting support added to the JTable, I cringe as I read part of it. All of this is very good, but the foundation of sorting should be this interface:

public interface SortableTableModel extends TableModel
{
  public Comparator getComparator(int row, int column);
}

That's it right there. It supports any implementation of sorting that you could possibly want. If you haven't made that the foundation of table sorting, please find a way to work it in.


Submitted On 03-JUN-2005
bassclar
Wait, am I reading the evaluation posted 2005-05-25 incorrectly, or does JTable 


Submitted On 03-JUN-2005
bassclar
Wait, am I reading the evaluation posted 2005-05-25
incorrectly, or does JTable "now offer" sorted based
solely on conversion to Strings?

JTable should handle sorting in a way simalarly to the
Collections framework. Sort order should default to a
column class's natural order (see java.lang.Comparable
interface) and the user should be able to specify a
custom Comparator (see java.util.Comparator) if s/he
wishes.

Falling back on a lexical String ordering is ok if the
column elements aren't Comparable or if their Comparators
throw exceptions at runtime.

Is it too late to get one or more of the Collections
peolpe to consult on this RFE.



PLEASE NOTE: JDK6 is formerly known as Project Mustang