javaswingjtabletablecellrendererrowsorter

How to sort dates in a column in a JTable?


I have the following jtable jtable image I get the information from a database and everything is saved as string in the table, I just want to sort the second column "Fecha de recepcion" which has dates in the format dd-mm-yyyy, I used a row classifier but it takes the dates as strings.

I made a TableCellRenderer for just that column and applied the following properties

Table.getColumnModel().getColumn(1).setCellRenderer( new Render());
Table.setAutoCreateRowSorter(true);

but it still sorts it as string.

I would really appreciate if someone can guide me on what I'm doing wrong

This is my class that implements TableCellRenderer

public class Render implements TableCellRenderer{
     private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
        LocalDate  date = LocalDate.parse(value.toString(),formatter);
        Component c = renderer.getTableCellRendererComponent(table,
                date, isSelected, hasFocus, row, column);
        return c;
    }
}

Solution

  • The important thing here is the data, what's in the TableModel, as this is what the table will use to sort by.

    Based on LocalDate date = LocalDate.parse(value.toString(),formatter); it would appear that your data is String based, which will be the cause of you core problem.

    Instead, you data should be using LocalDate. LocalDate is comparable by default, so you don't need any "special" comparators or additional support, it will "just work" out of the box, for example, unsorted, descending, ascending...

    enter image description here

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.EventQueue;
    import java.time.LocalDate;
    import java.time.format.DateTimeFormatter;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ThreadLocalRandom;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.table.AbstractTableModel;
    import javax.swing.table.DefaultTableCellRenderer;
    
    public class Main {
        public static void main(String[] args) {
            new Main();
        }
    
        public Main() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            public TestPane() {
                setLayout(new BorderLayout());
                long minDay = LocalDate.of(1970, 1, 1).toEpochDay();
                long maxDay = LocalDate.of(2015, 12, 31).toEpochDay();
                List<LocalDate> dates = new ArrayList<>(100);
                for (int index = 0; index < 100; index++) {
                    long randomDay = ThreadLocalRandom.current().nextLong(minDay, maxDay);
                    dates.add(LocalDate.ofEpochDay(randomDay));
                }
    
                JTable table = new JTable(new ExampleTabelModel(dates));
                table.setDefaultRenderer(LocalDate.class, new DateCellRenderer());
                table.setAutoCreateRowSorter(true);
                add(new JScrollPane(table));
            }
        }
    
        public class DateCellRenderer extends DefaultTableCellRenderer {
            private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                if (value instanceof LocalDate) {
                    value = ((LocalDate) value).format(formatter);
                }
                return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            }
        }
    
        public class ExampleTabelModel extends AbstractTableModel {
            private List<LocalDate> dates;
    
            public ExampleTabelModel(List<LocalDate> dates) {
                this.dates = dates;
            }
    
            @Override
            public String getColumnName(int column) {
                switch (column) {
                    case 0: return "Rows";
                    case 1: return "Dates";
                }            
                return null;
            }
    
            @Override
            public int getRowCount() {
                return dates.size();
            }
    
            @Override
            public int getColumnCount() {
                return 2;
            }
    
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                switch (columnIndex) {
                    case 0:
                        return Integer.class;
                    case 1:
                        return LocalDate.class;
                }
                return Object.class;
            }
    
            @Override
            public Object getValueAt(int rowIndex, int columnIndex) {
                switch (columnIndex) {
                    case 0:
                        return rowIndex;
                    case 1:
                        return dates.get(rowIndex);
                }
                return null;
            }
        }
    }