Search code examples
javaswingjtabletablecelleditor

JTable setting a default editor for a custom class


I am having an issue with trying to set a default JTable cell editor for a custom class. I have several custom columns (numbers, strings and booleans). For the number types I use a my own cell editors and for the boolean and string types I just wanted to use the default ones provided by the JTable class.

I have the following code in the setup of my table:

JTable table;
....
table.setDefaultEditor(MyBoolean.class, table.getDefaultEditor(Boolean.class));
table.setDefaultRenderer(MyBoolean.class, table.getDefaultRenderer(Boolean.class));
table.setDefaultEditor(MyString.class, table.getDefaultEditor(String.class);
table.setDefaultRenderer(MyString.class, table.getDefaultRenderer(String.class);

The boolean type works as expected and I can click on the tickbox and have it turn on and off. The string type displays but will not let me edit. In my model I have it so that all columns return true for editable.

If I add the following to my model:

@Override
public Class<?> getColumnClass(int columnIndex){
    Class<?> clz = columns.get(columnIndex).getClass();
    if(clz.isAssignableFrom(MyString.class)){
        return String.class;
    }
    return clz;
}

I can now edit the strings as expected.

My question: Why does setting the default editor not work for the string class but does for the boolean class? Why do I have to have a special case in the getColumnClass method in the model?


Solution

  • I figured out why it was behaving the way I described originally. It finally clicked when I looked at the setValueAt method:

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
       rows.get(rowIndex).getValues().set(columnIndex, aValue);
       fireTableCellUpdated(rowIndex, columnIndex);
    }
    

    and noticed that Object was an instance of MyString and the result in the cell came from Object.toString().

    The reason MyString came through to the method is because the GenericEditor in JTable (which covers the String class) has the method getTableCellEditorComponent which creates a java.lang.reflect.Constructor object that is used to instantiate new instances of the objects allowed in this column. MyString column class had a constructor that took a String and hence it returned a new MyString column instance to the setValueAt method. When I changed the code in getColumnClass (as shown above) to return String.class, a new instance of String was created when the editing stopped and it was passed to the setValueAt method and hence correctly displaced in the cell.

    Definitely learned a lot about JTables with this problem.