![]() ![]() ![]() |
9
Sortable Table
Features of JCMappingSort
Features of JCSortableTable
Classes and Interfaces
Constructors and Methods
Examples
9.1 Features of JCMappingSort
Sorting can be accomplished by indexing the list of objects that are going to be ordered according to some comparison policy. It can be much more efficient to sort these indices instead of sorting the objects themselves. The idea is to form an array of indices. Initially, a[1] = 1, a[2] = 2, and so on, up to n, the length of the list. After sorting, the result might be a[1] = 9, a[2] = 3, ... a[n-1] = 1, ... a[n] = 7, where now the index in a[1] corresponds to the object that is the smallest element in the list according to the supplied comparison rule. The index in a[2] corresponds to the next smallest object, and so on. The list hasn't changed, but the array supplies a mechanism for traversing the list according to some ordering principle.
The foregoing paragraph shows you that if you want to use this type of mapping sort in your application, you'll need to supply an array of indices and a comparator to use with your list. In some cases, a comparator is already available. A number of common objects implement the
Comparable
interface in Java 2. You can compare any of these types without needing to supply an explicit comparator.
JCMappingSort
provides asort()
method, which takes an implementation ofJCIntComparator
and an array of indices as parameters, and modifies the passed-in array based on thecompare()
method defined by your implementation ofJCIntComparator
.
9.2 Features of JCSortableTable
JCSortableTable
uses a comparator and a configureable list of column indices, making this class useful for establishing a sort policy that specifies what should be done when two elements in the primary column have the same value. Elements in the primary column that compare the same are arranged among themselves by sorting the secondary column. The process can be continued as necessary by including more columns in the list.
- Each column in a table may have an associated list of columns that are to be used as sort keys. Normally, the column itself is specified as the primary sort key.
- You can set whether a table is re-sorted automatically when its data changes.
- You can set or toggle the sorting order, permitting sorting from less to greater, or from greater to less.
- Sort
Date
s,Object
s that implementComparable
, and wrapped primitive types.- You can provide your own implementation of
JCRowComparator
to perform row comparisons in the sort algorithm. See the example at the end of this chapter for details.
9.3 Classes and Interfaces
JCMappingSort
You'll find these classes and interfaces in
com.klg.jclass.util
.JCSortableTable
Using your own comparator with JCSortableTable
If you wish to provide your own comparator for a
JCSortableTable
, follow these steps:Note that the data model you set in step 2 should be a
JCRowSortTableModel
. If it is not,JCSortableTable
will wrap the data model you provide with aJCRowSortTableModel
.
9.4 Constructors and Methods
Constructors for JCSortableTable
The core of the sorting mechanism is based on providing the
public static void sort(JCIntComparator comparator, int indices[])sort()
method with a list of indices specifying an ordered list of columns on which the sort is to be based:
public static void sort(JCIntComparator comparator, int indices[], int start, int end)Both methods require a
JCIntComparator
and an array of indices. The second method includes two additional parameters that are useful in many sorting algorithms.Methods
In addition to the host of methods it inherits from
JTable
,JCSortableTable
adds many of its own:
9.5 Cell Renderers for JCSortableTable
Normally, you do not need to be concerned with the details of how table cells are rendered because renderers for most common cases have already been supplied. On the other hand, you may wish to use a custom renderer of your own design. While it is possible to use
setDefaultRenderer()
to set a cell renderer for aJTable
, the method is not available for use withJCSortableTable
. Instead, JClass uses its own powerful cell editor/renderer mechanism. This allows all JClass products to manage collections ofJCCellRenderer
types uniformly instead of having to manage the renderer types separately. To set your own cell renderer, use JClass Cell'sEditorRendererRegistry
, and implement one of the renderer interfaces. Please see the com.klg.jclass.cell API for details.
9.6 Examples
JCMappingSort example
JCMappingSort
cannot be instantiated by calling its constructor. Instead, it has two static methods of the form:
public static void sort(JCIntComparator compartor, int indices[]);
public static void sort(JCIntComparator compartor, int indices[],
int start, int end);The purpose of these two methods is to sort a mapping of indices instead of an array of objects. This is particularly useful when dealing with a
Collection
, or some form of data model where you reference a data element with an index. Your implementation of theJCIntComparator
interface provides the implementation details for the objects you are sorting.public interface JCIntComparator {
JCIntComparator
should look like this:
public int compare(int index1, int index2);
}The
public class CollectionComparator implements JCIntComparator {CollectionIntComparator
is a specific implementation ofJCIntComparator
that can compareCollections
. Sample code looks like this:
protected Collection collection;
protected Comparator comparator;
public CollectionComparator(Collection collection, Comparator comparator) {
this.collection = collection;
this.comparator = comparator;
}
public CollectionComparator(Collection collection) {
this(collection, null);
}
public int compare(int i1, int i2) {
Object a1 = collection.get(i1);
Object a2 = collection.get(i2);
if (comparator != null) {
// use comparator if provided
return comparator.compare(a1, a2);
}
else if (a1 instanceof Comparable) {
// items are comparable so get them to compare themselves
return ((Comparable) a1).compare(a2);
}
else {
// We have no comparator and the objects are not comparable
throw new IllegalArgumentException("Objects are not
Comparable; please provide a Comparator with the constructor:
CollectionComparator(Collection collection, Comparator comparator)");
}
}
}JCSortableTable examples
One use of
JCSortableTable
is given in examples/elements/SortTable.A full example based on
import java.awt.BorderLayout;SortTable.java
follows. It demonstrates sorting on columnar data containingString
s, and two types of primitives: Boolean values and integers. The example provides its own implementation ofJCRowComparator
to perform a comparison between two rows in the table.
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Comparator;
import java.text.*;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.table.AbstractTableModel;
import javax.swing.BoxLayout;
import javax.swing.table.DefaultTableCellRenderer;
import com.klg.jclass.util.swing.JCExitFrame;
import com.klg.jclass.util.swing.JCSortableTable;
import com.klg.jclass.util.swing.DefaultRowSortTableModel;
import com.klg.jclass.util.swing.DefaultRowComparator;
import com.klg.jclass.util.swing.JCRowSortModel;
import com.klg.jclass.util.swing.JCComparableRow;
/**
* Sorting is allowed on these columns:
* "First Name", "Last Name", "Position", "Favorite Number", and
* "Vegetarian"
*/
public class SortDateJCSortableTable extends JPanel implements
ActionListener {
protected final static String[] names =
{"First Name", "Last Name", "Position",
"Favorite Number", "Vegetarian",
"Calendar","GregorianCalendar"};
protected final static Object[][] data = {
{"Diana", "Zukerman", "Research Officer",
new Integer(1), new Boolean(false),"",""},
{"Adam", "Petersen", "Consultant",
new Integer(2), new Boolean(false),"",""},
{"Mary", "Binfield", "Research Associate",
new Integer(5), new Boolean(false),"",""},
{"Michael", "Rizzo", "Research Fellow",
new Integer(2), new Boolean(true),"",""},
{"Ahmad", "Baldi", "Consultant",
new Integer(3), new Boolean(false),"",""},
{"Ian", "Clemente", "Research Fellow",
new Integer(7), new Boolean(false),"",""},
{"David", "Rubinstein", "Consultant",
new Integer(4), new Boolean(false),"",""},
};
protected JButton buttonUnsort = null;
protected JCSortableTable sortableTable = null;
/** Indicates that the first object is less than the second object.
*/
public static final int LESS_THAN = -1;
/** Indicates that the first object is equal to the second object. */
public static final int EQUAL = 0;
/** Indicates that the first object is greater than the second object. */
public static final int GREATER_THAN = 1;
public SortDateJCSortableTable() {
// Set a simple BoxLayout manager
setLayout(new BoxLayout(this,BoxLayout.X_AXIS));
//set up the calender values to be tested
for (int r =0 ; r < data[0].length ; r++){
Calendar c = Calendar.getInstance();
c.set(1998+r, r, 1);
GregorianCalendar gc = (GregorianCalendar)c;
data[r][5] = c;
data[r][6] = gc;
}
// Create and add the table
sortableTable = createTable();
add(new JScrollPane(sortableTable));
// Create and add an Unsort button for the table
buttonUnsort = new JButton("Unsort");
buttonUnsort.addActionListener(this);
add(buttonUnsort);
}
public static JCSortableTable createTable() {
EditableTableModel model = new EditableTableModel();
JCSortableTable table = new JCSortableTable();
// JCSortTable will do this anyway,
// but this way we have a member handle to it.
DefaultRowSortTableModel mRSmodel = new DefaultRowSortTableModel(model);
mRSmodel.setComparator(new MyComparator());
//set model and cast it down to the "DefaultRowSortTableModel"
table.setModel(mRSmodel);
// We use the last name if the first name is the same.
int sort0[] = {0, 1};
table.setKeyColumns(0, sort0);
// We use the first name if the last name is the same.
int sort1[] = {1, 0};
table.setKeyColumns(1, sort1);
// We use person's name if the department is the same.
int sort2[] = {2, 0, 1};
table.setKeyColumns(2, sort2);
//set the non primitive renderers, no editor defined for this example
table.getColumn("GregorianCalendar").setCellRenderer(new CGFCalendarCellRenderer());
table.getColumn("Calendar").setCellRenderer(new CGFCalendarCellRenderer());
return table;
}
public static void main(String args[]) {
JCExitFrame frame = new JCExitFrame("SortDateJCSortableTable Example");
SortDateJCSortableTable app = new SortDateJCSortableTable();
if (args.length > 0) {
if (args[0].equals("windows")) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception e) {}
}
}
frame.getContentPane().add(app);
frame.setBounds(50, 50, 650, 350);
frame.show();
}
//===== ActionListener interface method ========
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
sortableTable.unsort();
}
}
public static class CGFCalendarCellRenderer
extends DefaultTableCellRenderer
{
protected java.text.DateFormat date_formatter =
java.text.DateFormat.getDateInstance();
public void setValue(Object o)
{
String str = null;
if (o instanceof String) {
str = (String)o;
}
else if (o instanceof Calendar) {
str = date_formatter.format(((Calendar)o).getTime());
}
else {
str = o.toString();
}
super.setValue(o == null ? "" : str);
}
}
private static class EditableTableModel extends AbstractTableModel {
EditableTableModel() {
super();
}
public int getColumnCount() {
return names.length;
}
public int getRowCount() {
return data.length;
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public String getColumnName(int column) {
return names[column];
}
public Class getColumnClass(int col) {
return getValueAt(0,col).getClass();
}
// Disallow edits on dates, and on favorite number
public boolean isCellEditable(int row, int col) {
return col != 3 && col != 5 && col != 6;
}
public void setValueAt(Object aValue, int row, int column) {
data[row][column] = aValue;
}
} // EditableTableModel
static class MyComparator extends DefaultRowComparator {
public MyComparator(){
super(JCRowSortModel.FORWARD);
}
public int compare(JCComparableRow row1, JCComparableRow row2) {
int[] kc = super.getKeyColumns();
for (int i = 0; i < kc.length; i++) {
Object o1 = row1.getValueAt(kc[i]);
Object o2 = row2.getValueAt(kc[i]);
if(o1 instanceof Calendar && o2 instanceof Calendar) {
Calendar c1 = (Calendar)o1;
Calendar c2 = (Calendar)o2;
if(c1.equals(c2)) {
return EQUAL;
}
else if(c1.before(c2)) {
return LESS_THAN;
}
else {
return GREATER_THAN;
}
}
}
return super.compare(row1, row2);
}
}//MyComparator
} // SortDateJCSortableTable
![]() ![]() ![]() |