I am trying to get my JTable
to sort null values at the end of the table. This is similar to a thread found at SO (How can i sort java JTable with an empty Row and force the Empty row always be last?) and OTN (https://forums.oracle.com/thread/1351003) but the answers in those threads aren't very clear to me.
I did make a lot of progress using those answers, though, and I got as far as the SSCCE posted below. But I'm still trying to figure out how to get the null values (or, in the SSCCE I posted, the NullClassFiller
s) to always go to the bottom of the sort. I feel like if I could within the custom Comparator
somehow know which direction was being sorted (ascending or descending), I could get this easily to work. But Comparator
doesn't know the sort direction...
Anyone?
import java.awt.Component;
import java.util.Comparator;
import javax.swing.DefaultRowSorter;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
public class Test {
public static void main(String args[]) {
JFrame frame = new JFrame();
JTable table = new JTable();
Object[][] data = new Object[8][3];
data[0][0] = 6.5d; data[0][1] = "Name1";
data[1][0] = new NullClassFiller(); data[1][1] = "Name2";
data[2][0] = 2.6d; data[2][1] = "Name3";
data[3][0] = 0d; data[3][1] = "Name4";
data[4][0] = new NullClassFiller(); data[4][1] = "Name5";
data[5][0] = -4d; data[5][1] = "Name6";
data[6][0] = 0d; data[6][1] = "Name7";
data[7][0] = -4.3d; data[7][1] = "Name8";
table.setModel(new DefaultTableModel(data, new String[]{"One", "Two"}));
table.setAutoCreateRowSorter(true);
DefaultRowSorter<?, ?> sorter = (DefaultRowSorter<?, ?>) table.getRowSorter();
sorter.setComparator(0, new CustomComparator());
table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer());
JScrollPane pane = new JScrollPane(table);
frame.add(pane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setSize(500, 500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
static class CustomComparator implements Comparator<Object> {
@Override
public int compare(Object d1, Object d2) {
if (d1 instanceof NullClassFiller) {
return -1;
} else if (d2 instanceof NullClassFiller) {
return -1;
} else {
return ((Comparable<Object>) d1).compareTo(d2);
}
}
}
static class NullClassFiller {}
static class CustomRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if(value instanceof NullClassFiller)
renderer.setText("");
return renderer;
}
}
}
I solved the problem thanks to @MadProgrammer and @kleopatra through a follow-up question (Java Comparator always reading values as Strings) I had.
The answer is to create a custom
Comparator
that can determine which way the table is being sorted, then return the right value accordingly (if the sort isASCENDING
theno1
needs to return1
, and-1
visa versa, ando2
is exactly the opposite).In my opinion, which is not worth much, this is not TOO hackish and does solve my problem, so I'm satisfied, even if others are not.
Here is the complete code to my solution:
In my original post, I was creating a custom
Comparator
, but it had no access togetSortKeys()
. So, I overwrote thegetComparator()
method in theTableRowSorter
so that I could accessgetSortKeys()
. It works.