javaswingsortingswingxjxtable

JXTable Incorrect Sorting


I am using a JXTable to display, filter, and sort some data. However, I'm getting some unexpected behavior when sorting. As you can see, the values are not ascending as expected, but sorted how a string would be sorted.

To address the comments, I am sure this column is getting parsed in the correct part of the code (i.e. the Float.valueOf() block.) I know this through debugging. Also, I am sorting the column by clicking on the jxtable's header. I am not doing it programmatically.

Incorrect Sort Order

Just to be clear, I am adding them as Floats:

class FantasyProTableModel extends DefaultTableModel
{
   void loadData() throws BiffException, IOException
   {
      Workbook workbook = Workbook.getWorkbook(new File("Input.xls"));
      Sheet sheet = workbook.getSheet(0);

      int numCols = sheet.getColumns();
      for(int col=0;col<numCols;col++)
      {
          addColumn(sheet.getCell(col,0).getContents());
      }
      for(int rownum=1;rownum<sheet.getRows();rownum++)
      {
          Object[] row = new Object[numCols];
          for(int col=0;col<numCols;col++)
          {
              try
              {
                  row[col] = Float.valueOf(sheet.getCell(col,rownum).getContents());
                                 //parseFloat() doesn't work either
              }
              catch(NumberFormatException e)
              {
                  row[col] = sheet.getCell(col,rownum).getContents();
              }
          }
          addRow(row);
      }

      workbook.close();
   }
}

What can I do to get it to sort in the correct, ascending order, by value?


Solution

  • Okay, after much digging, I've found two things, one, JXTable has it's own "row sorter", which wraps the default one and two, because DefaultTableModel returns Object.class by default from getColumnClass, these things are getting screwed up (SwingX's sorter is trying to make use of the Comparator interface, but if the object class is not comparable, then it defaults to using toString)

    You have two choices...

    You can...

    Implement the getColumnClass from DefaultTableModel and return a proper class reference...

    DefaultTableModel model = new DefaultTableModel(0, 1) {
        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return Float.class;
        }
    };
    

    Or you can...

    Provide your own comparator of the JXTable row sorter implementation...

    ((TableSortController)table.getRowSorter()).setComparator(0, new Comparator<Float>() {
        @Override
        public int compare(Float o1, Float o2) {
            return o1.compareTo(o2);
        }
    });