Search code examples
javaswingtablemodel

Java Swing's TableModel getValueAt responsibility


What responsibilities fall with Java Swing's TableModel...

Who should present the formatted display to the user?
Is there any official guidance?

JavaDocs

The help for getValueAt states:

Returns the value for the cell at columnIndex and rowIndex.

There is no mention of formatting here. It returns "the value" for the cell. An Object.

I have seen different implementations - even in products I have worked on. I feel there isn't much consistency.

Examples

TableModel

DecimalFormat decimalFormat = new DecimalFormat("#.###");

@Override
public Object getValueAt(int row, int column) {
    ...
    decimalFormat.format(myObjectModel.GetFoo(row).getSomeDoubleProperty());
}


DefaultTableCellRenderer

public final class PositionDoubleCellRenderer extends DefaultTableCellRenderer {

    private final String formatPattern = "%,.03f";

    @Override
    public Component getTableCellRendererComponent(
            final JTable table, Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column
    ) {
        String formattedValue = "";

        if (value instanceof Double) {
            double numeric = (Double) value;

            if (ConstantsModel.isConstant(numeric)) {
                formattedValue = "";
            } else {
                formattedValue = String.format(formatPattern, numeric);
            }
        }

        return super.getTableCellRendererComponent(table, formattedValue, isSelected, hasFocus, row, column);
    }
}

There are pro's and con's depending on which mechanism you use. I don't know of any other ways to format off the top of my head, but I have had this thought on my mind for a while now.


Solution

  • Who should present the formatted display to the user?

    The view. The JTable uses renderers to format/display the data.

    in order to have consistent formatting of data in different tables for doubles, you then have to open up each table model and change for getValueAt

    The data should not change. Therefore the getValueAt(...) method should not change.

    A renderer can be shared by multiple tables.

    You can even change the way the data is presented to the table by overriding the getColumnClass(...) method of a JTable.

    The table has some default renderers for Boolean.class, Number.class, Icon.class etc.

    So, for example if you have an Integer value stored in the model and if you override the getColumnClass(...) method of the table to return:

    1. Integer.class - the data will be formatted as a number and displayed right aligned
    2. Object.cloass - the data will be treated like a String and displayed left justified.

    Or you can even assign a custom renderer to a specific column in the TableColumnModel. So if you wanted the Integer formatted as a "percentage" you can use a renderer for that.

    So, bottom line is the same data can be displayed in an unlimited number of ways when the proper renderer is used.

    Check out Table Format Renderers for an easy way to create reusable formatting renderers.