Hi I am trying to use a custom comparator for only a single column in the JTable. I have accomplished this with the following code. The problem is that doing this breaks the appropriate sort for Integer.
I have a JTable where the column classes are: String | Integer | Integer | Boolean | Boolean
The Comparators I'm using are these. The first uses a split from How to split a string between letters and digits (or between digits and letters)?.
//compare strings being aware of numbers embedded in the string
private static Comparator<String> numberAwareCompare = new Comparator<String>() {
public int compare(String s1, String s2) {
String[] s1Parts = s1.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
String[] s2Parts = s2.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
int i = 0;
while(i < s1Parts.length && i < s2Parts.length){
//if parts are the same
if(s1Parts[i].compareTo(s2Parts[i]) == 0){
++i;
}else{
try{
int intS1 = Integer.parseInt(s1Parts[i]);
int intS2 = Integer.parseInt(s2Parts[i]);
//if the parse works
int diff = intS1 - intS2;
if(diff == 0){
++i;
}else{
return diff;
}
}catch(Exception ex){
return s1.compareTo(s2);
}
}//end else
}//end while
//Handle if one string is a prefix of the other.
if(s1.length() < s2.length()){
return -1;
}else if(s1.length() > s2.length()){
return 1;
}else{
return 0;
}
return 0;
}
};
I extend the TableRowSorter as follows:
public class FeatureRowSorter extends TableRowSorter<TableModel>{
public FeatureRowSorter(TableModel tableModel) {
super(tableModel);
//setComparator(0, numberAwareCompare);
//setComparator(1,intCompare);
//setComparator(2,intCompare);
}
@Override
public Comparator<?> getComparator(int column){
if(column == 0){
return numberAwareCompare;
}else{
return super.getComparator(column);
}
}
}
This results in the following undesired sort behavior:
This can be overcome by creating an Integer sort. This is the issue. I should not have to create a sort for Integer. If the default TableRowSorter knows the class is Integer why can it not create it?
So I create a trivial Integer sorter as follows:
//Integer compare, need this to use the custom TableRowSorter
public static Comparator<Integer> intCompare = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
};
Now I delete the getComparator method above and explictly add the comparators to the correct columns. (The commented out code above). This has the correct sorting behavior.
I add the row sorter to the table with the following code. My model creates a new custom row sorter and sends it to the view's JTable in a controller object.
//In the model, FeatureTableModel extends DefaultTableModel,getClass method implemented correctly
public FeatureRowSorter getFeatureRowSorter(){
return new FeatureRowSorter(getFeatureTableModel());
}
Then add the sorter to the table like so:
view.getFeatureTable().setRowSorter(model.getFeatureRowSorter());
So the question is, how would I do this with out having to implement the Integer sorter? This seems like a hack, and the fact that I'm implementing an Integer comparator seems fishy. The TableRowSorter knows those columns are Integer because of the FeatureTableModel's getClass method which is implemented correctly. (Nevermind that one of the boolean columns is not checkbox. I'm overriding that renderer).
Any suggestion would be appreciated.
UPDATE:
After reading Duncan's answer I found I had not imiplemented getClass correctly. I had:
@Override
public Class<?> getColumnClass(int column){
if(column == 4){
return Boolean.class;
}else if(column == 2){
return Integer.class;
}else{
return Object.class;
}
}
I changed this to:
@Override
public Class<?> getColumnClass(int column){
if(column == 4){
return Boolean.class;
}else if(column == 1 || column == 2){
return Integer.class;
}else{
return Object.class;
}
}
Based on a quick bit of testing, I achieved the desired results by calling the
setComparator
method on theTableRowSorter
instance. That is, I didn't create my own class that extendsTableRowSorter
.In my test, this approach had no negative affects on the ability to sort a column of integers in the same table.
I appreciate this isn't an explanation of why you are encountering problems, but it is worth a shot as a potentially simpler work-around.