2

I have read several questions about JTable sorting:

Problems with JTable sorting of integer values

JTable + Sorting specific field

but I still can't manage to get it right, for some reason.

I have written this:

String allItemsColumns [] = { "#", "Name", "Stock", 
    "Price", "Type", "Supplier", "Location", "" };
allItemsTableModel = new DefaultTableModel(null, allItemsColumns);
allItemsTable = new JTable(allItemsTableModel)
{       
    Class<?>[] types = { Integer.class, String.class, Integer.class, 
         Double.class, String.class, String.class, String.class, ImageIcon.class };

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return this.types[columnIndex];
    }
};

but I still get

0
10000
20

when I sort stock. Probably it's an obvious one, but I'm really missing it at the moment.

I do not think it matters how I add info as I (think so that) tell it to read the columns as Integers, Doubles or Strings

My sorting method:

allItemsTable.setAutoCreateRowSorter(true);
TableRowSorter<DefaultTableModel> rowSorter = 
     (TableRowSorter<DefaultTableModel>)allItemsTable.getRowSorter();
rowSorter.setComparator(3, new Comparator<String>() {

    @Override
    public int compare(String o1, String o2)
    {
        return Integer.parseInt(o1) - Integer.parseInt(o2);
    }

});

I have taken it from one of the questions I saw. Column #3 is "Stock" which is Integers only, but the result, like I said is:

0
10000
20
Community
  • 1
  • 1
Nikola
  • 2,093
  • 3
  • 22
  • 43

2 Answers2

4

To summarize my various comments:

  • TableRowSorter can and does sort Comparable types as expected
  • getColumnClass is the key to provide the sorter with the means of correct sorting as it determines which default Comparator is used
    • if the return type is a Comparable, it's a comparator implementation that delegates to it
    • if the return type is not a Comparable, the Collator instance is used and fed with the value's string representation, no matter whether it's actual type is Comparable or not

So there is no need for a custom comparator in columns containing values that are comparable to each other, just implement the columnClass to return that type and be done.

Here's a snippet demonstrating the behaviour (throw it into you favourite test setup, just any frame will do). First column is defined as Integer which is-a Comparable, second as a Number which !is-a Comparable, others simply Object. All actual values are ints. The first column is sorted numerically, all others by their string representation

final Class[] classes = new Class[]{Integer.class, Number.class};
DefaultTableModel model = new DefaultTableModel(0, 3) {

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        if (columnIndex < classes.length) 
            return classes[columnIndex];
        return super.getColumnClass(columnIndex);
    }

    @Override
    public String getColumnName(int column) {
        return getColumnClass(column).getSimpleName();
    }

};
for (int row = 0; row < 15; row++) {
    model.addRow(new Object[]{row, row, row});
}
JTable table = new JTable(model);
table.setAutoCreateRowSorter(true);

If implementing the columnClass (btw: that should be done in the model, not the view!) appears to not be working in a concrete context, there's some problem elsewhere which should be tracked down (it will hit again sooner or later)

kleopatra
  • 51,061
  • 28
  • 99
  • 211
0

As far as I know, getColumnClass() has no effect on sorting. It is used for determining editors.

If you are adding string representations of numbers and expecting them to sort numerically, then that's your problem. Add them as numeric types, and it should work. The sort is based on the values in the TableModel implementing the Comparable interface.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
GreyBeardedGeek
  • 29,460
  • 2
  • 47
  • 67
  • I have added my (or rather the one I use) implementation of Comparator which wouldn't work for me – Nikola May 26 '13 at 02:13
  • 1
    Column #3 is actually the price column. Remember, Java is 0 based – MadProgrammer May 26 '13 at 04:37
  • wrong, getColumnClass() is most important identifier for RowSorter/Filter, wrong, JTable has most efficient comparator, – mKorbel May 26 '13 at 12:23
  • @MadProgrammer if we consider it starts from 0 and I put 2 (so it can be the #3 column) I get an exception: Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String – Nikola May 26 '13 at 13:43
  • @mKorbel - you are partially correct, however, for the OP's use case, I believe that my answer was correct - the documentation states: "If the column class returned by TableModel.getColumnClass implements Comparable, use a comparator that sorts the strings based on the values returned by Comparable.compareTo" see http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#sorting – GreyBeardedGeek May 26 '13 at 16:24
  • please for why hell on this world we needed custom comparator for basic data types supported through whole Java APIs, am I wrong that I'm against complicating the simple things, issue must be somewhere in the rest of code..., TableModel contains String instance, Renderer doing something wrong, against natural rulles, dot :-) – mKorbel May 26 '13 at 18:45
  • I never suggested a custom comparator. I suggested that the TableModel be populated with Number types. AFAIK, all of the Number subclasses implement Comparable, so sorting should then just work. Having Strings in the TableModel, and expecting them to sort numerically is the cause of the 'problem'. – GreyBeardedGeek May 27 '13 at 01:56
  • your first sentence is plain wrong: the columnClass is used to decide which default comparator to use (if none is explicitly set for a column) The second paragraph is wrong as well (not overly surprising, though, with the incorrect assumption of the first ;) - adding comparable types without implementing columnClass accordingly, will sort them by their toString values – kleopatra Jun 24 '13 at 08:40