110
|
Chapter 3, Tables and Trees
#23 Let Your JTables Do the Sorting
HACK
H A C K
#23
Let Your JTables Do the Sorting Hack #23
Why doesn’t Swing already offer this? Oh well, here’s how to do it yourself.
It’s hard to imagine you’ll do much serious work with JTables without need-
ing to sort the contents by one of the columns, or support changing between
columns to use as the sort criteria. In fact, given how generous the Swing
API usually is, it’s kind of surprising that it doesn’t already offer it. Oh well,
it’s not that hard to do for yourself.
There are a couple of approaches you could take to solve this problem. You
could create a subclass of
TableModel, one that keeps an internal Comparator
to do the sorting and resorts every time an add( ) or remove( ) type method is
called. The drawback to this approach is choosing which of the model
classes to subclass. If you go too high up the hierarchy by implementing
TableModel or subclassing DefaultTableModel, you would miss some typical
Swing functionality that developers expect, like the ability to add and
remove rows provided by
DefaultMutableTableModel. On the other hand, if
you subclass
DefaultMutableTableModel, other developers will be unhappy
because subclassing your class requires them to pick up public
add( ) and
delete( ) type methods that expose their data in ways they don’t want.
So, consider an alternative: two table models, one that the
JTable sees and
another that the developer sees. Specifically, the developer will pass her
TableModel to the constructor of the sorting model, which will wire up for
events on the model. Then, the developer will set the sorting model as the
JTable’s model. Changes in the base model will force the sorting model to
resort its contents and then fire off events to
JTable to drive updates to the
onscreen representation.
There are more details in the actual implementation of course, particularly
when it comes to doing the sorting. Example 3-5 shows the code for the
SortableTableModel.
Figure 3-4. Selecting JTable columns by clicking on headers
Let Your JTables Do the Sorting #23
Chapter 3, Tables and Trees
|
111
HACK
Example 3-5. Self-sorting TableModel
public class SortableTableModel implements TableModel,
TableModelListener {
EventListenerList listenerList = new EventListenerList( );
TableModel delegatedModel;
int[] sortedIndicies;
int sortColumn;
Comparator comparator;
Comparator[] comparators;
public SortableTableModel (TableModel tm) {
delegatedModel = tm;
delegatedModel.addTableModelListener (this);
comparators = new Comparator [tm.getColumnCount( )];
sortedIndicies = new int [0];
setSortColumn (0);
}
// listener stuff
public void addTableModelListener (TableModelListener l) {
listenerList.add (TableModelListener.class, l);
}
public void removeTableModelListener (TableModelListener l) {
listenerList.remove (TableModelListener.class, l);
}
public void fireTableModelEvent (TableModelEvent e) {
Object[] listeners = listenerList.getListenerList( );
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i] == TableModelListener.class) {
((TableModelListener) listeners[i+1]).tableChanged(e);
}
}
}
// contents stuff
public Class getColumnClass(int columnIndex)
if (delegatedModel.getRowCount( ) > 0)
return delegatedModel.getValueAt(0, columnIndex).getClass( );
else
return Object.class;
}
// getColumnCount(), getColumnName(), getRowCount( ),
// getValueAt(), isCellEditable(), setValueAt( ) listings below
// internal helpers
public void setComparatorForColumn (Comparator c, int i) {
112
|
Chapter 3, Tables and Trees
#23 Let Your JTables Do the Sorting
HACK
// range check
if (i > comparators.length) {
Comparator[] newComparators = new Comparator[i+1];
System.arraycopy (comparators, 0,
newComparators, 0,
comparators.length);
comparators = newComparators;
}
// add the comparator
comparators[i] = c;
}
public void setSortColumn (int i) {
sortColumn = i;
// reset current comparator, possibly to null, which
// will make us use "natural ordering" for those values
comparator = null;
if ((comparators != null) &&
(comparators.length > 0))
// is there one in the list of comparators?
comparator = comparators[sortColumn];
// now do the sort
resort( );
}
public int getSortColumn ( ) {
return sortColumn;
}
// resort( ) method listed below
// SortingDelegate inner class listed below
// SortingDelegateComparator inner class listed below
public void tableChanged (TableModelEvent e) {
switch (e.getType( )) {
case TableModelEvent.DELETE: {
resort( );
fireAllChanged( );
break;
}
case TableModelEvent.INSERT: {
resort( );
fireAllChanged( );
break;
}
case TableModelEvent.UPDATE: {
resort( );
fireAllChanged( );
break;
Example 3-5. Self-sorting TableModel (continued)

Get Swing Hacks now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.