AxelF
AxelF

Reputation: 109

Swing: binding complex object list with jtable

I'm developping a small application in Swing with Netbeans. I currently can display a list of objects in a jTable with Binding. But one of the object's properties is another object:

public class CustomProp {
    private String description;
    private int value;

    //constructor, getters and setters...
}

public class MainObject {
    private int id;
    private String name;
    private boolean aBoolProp;
    private CustomProp myCustomProp;

    //constructors, getters and setters...
}

I have a arraylist with 4 instanced MainObjects named mainObjectsList. The jTable Elements binding espression is ${mainObjectsList}

Then in the jTable, I can see my objects properties but in myCustomProps column, I can see only the object address (mytest.CustomProp@64ca87d5). Is it possible to configure the Binding expression to display the parameters of the object property in the jTable?

Upvotes: 0

Views: 3633

Answers (1)

Boris the Spider
Boris the Spider

Reputation: 61198

To understand what is going on you need to understand how a JTable turns what you give it into a displayable component.

This is does using a TableCellRenderer. What this essentially does it create a JLabel for each table cell that contains a String representation of the data.

The default renderer doesn't have any idea about your CustomProp type so all it does it call toString on it to get a String representation and display it.

This opens one avenue - change the toString of your CustomProp. This approach will work, but is hacky for a number of reasons:

  1. Your object should not really be tempting itself, this is a violation of separation of concerns.
  2. You toString method may well be used elsewhere, in logging for example, and the representation that makes sense in the table will not make sense there
  3. toString should not really be part of an object's contract - it should be changeable when new fields are added etc. If you use the representation in the table then that is not the case (see 1.)

Having said that, Joshua Bloch's Item 10 ("Always override toString") does state that toString can be part of an object's contract if it is heavily documented.

Personally, I would prefer to set the column class of the TableModel by extending DefaultTableModel:

private static final class MyTableModel extends DefaultTableModel {

    private static final int CUSTOM_PROP_COL = 1;

    //various required constructors, call super(...)

    @Override
    public Class<?> getColumnClass(final int columnIndex) {
        if (columnIndex == CUSTOM_PROP_COL) {
            return CustomProp.class;
        }
        return super.getColumnClass(columnIndex);
    }

}

Then you need to set this model rather than the default when you build your JTable:

final MyTableModel myTableModel = /*create as usual*/  
final JTable jTable = new JTable(myTableModel);

Now your table knows the class of the column with CustomProp. Create a custom renderer to render the column:

private static final class CustomPropRenderer extends DefaultTableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        final CustomProp prop = (CustomProp) value;
        final StringBuilder representation = new StringBuilder();
        //build a string representation of prop
        return super.getTableCellRendererComponent(table, representation.toString(), isSelected, hasFocus, row, column);
    }

}

And tell your JTable to use your renderer for columns of class CustomProp:

jTable.setDefaultRenderer(CustomProp.class, new CustomPropRenderer());

EDIT

Following @kleopatra's comment and noticing the tag I did a quick google and found this previous SO post. Looks like it is either exactly what is required (or possible completely irrelevant).

You should be able to use ${customProp.property} as the binding for the column.

Upvotes: 4

Related Questions