javaswingjtabletablemodel

Are row and column indices that TableCellEditor#getTableCellEditorComponent() receives view coordinates?


I'm writing a TableCellEditor implementation which needs to fetch some data from underlying TableModel. In order to do that, I need row and column indices for TableModel.

What I'd like to know is whether the indices getTableCellEditorComponent() receives are view coordinates or model coordinates. In other words, are the table.convertRowIndexToModel() and table.convertColumnIndexToModel() calls in the following code necessary? Or is it ok to just pass those indicies to model.getValueAt() directly?

class MyTableCellEditor implements TableCellEditor {

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        TableModel model = table.getModel();

        // is this necessary?
        int rowForQueryingModel = table.convertRowIndexToModel(row);
        int colForQueryingModel = table.convertColumnIndexToModel(column);

        Object valueFromModel = model.getValueAt(rowForQueryingModel, colForQueryingModel);
        return createComponent(valueFromModel);
    }
   ...
}

Solution

  • The cell renderer receives view coordinates. This is useful for doing things like coloring even and odd lines or columns differently, etc. Fetching data has not been considered the primary goal, as the actual value is already provided as parameter.

    If you need to access the model data for some reason, you have to convert the coordinates.

    You can easily check this with a simple example program:

    public class CellRendererTest {
        public static void main(String... args) {
            if(!EventQueue.isDispatchThread()) {
                EventQueue.invokeLater(CellRendererTest::main);
                return;
            }
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch(ReflectiveOperationException | UnsupportedLookAndFeelException ex) {}
    
            JFrame frame = new JFrame("Test");
            Object[][] data = new Object[10][10];
            String[] name = new String[10];
            for (int ix = 0; ix < data.length; ix++) {
                data[ix][0] = ix + 1;
                data[ix][1] = new String(Character.toChars('A' + ix % 3));
                name[ix] = new String(Character.toChars('A' + ix));
            }
            JTable table = new JTable(data, name);
            table.setAutoCreateRowSorter(true);
            DefaultTableCellRenderer r = new DefaultTableCellRenderer();
            table.setDefaultRenderer(Object.class, (t, val, s, f, row, column) ->
                    r.getTableCellRendererComponent(t, val != null? val: row+", "+column,
                                                    s, f, row, column));
            frame.setContentPane(new JScrollPane(table));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setVisible(true);
        }
    }
    

    You can change the column order by dragging the column header or reorder the rows by clicking on A’s or B’s column header to sort the data, but the other cells displaying the row and column arguments provided to the renderer will keep reflecting their visual position.