JTable - редактор нескольких ячеек в одном столбце

Я бы хотел, чтобы мой JTable использовал разные редакторы ячеек для разных ячеек в одном столбце. Подумайте о таблице значений таблиц с двумя столбцами, например:

Name          | Value
--------------+--------------------------------
Identifier    | ST33442 (string editor)
Purchase Date | 7/7/10 (custom calendar editor)
Status        | Broken (combo editor)

Как я могу построить редактор динамически? Что-то вроде TableCellEditorFactory было бы идеальным.

Ответ 1

Вам нужно реализовать собственный редактор ячеек и назначить его столбцу. Вероятно, вы должны сделать то же самое с средством визуализации ячеек (так, например, booleans будет отображаться как флажок вместо "true" / "false" ).

public class TableEditorTest {

    public static void main(String[] args) {
        Object[][] data = new Object[][] {{"Identifier", "ST33442"}, {"Purchase Date", new Date()}, {"Status", Boolean.FALSE}};
        String[] columnNames = new String[] {"Name", "Value"};
        TableModel model = new DefaultTableModel(data, columnNames);
        JTable table = new JTable(model);
        JScrollPane scrollPane = new JScrollPane(table);
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(scrollPane);
        frame.pack();
        frame.setVisible(true);

        table.getColumnModel().getColumn(1).setCellEditor(new CustomTableCellEditor());
    }

    public static class CustomTableCellEditor extends AbstractCellEditor implements TableCellEditor {
        private TableCellEditor editor;

        @Override
        public Object getCellEditorValue() {
            if (editor != null) {
                return editor.getCellEditorValue();
            }

            return null;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            if (value instanceof Date) {
                editor = new DatePickerCellEditor();
            } else if (value instanceof String) {
                editor = new DefaultCellEditor(new JTextField());
            } else if (value instanceof Boolean) {
                editor = new DefaultCellEditor(new JCheckBox());
            }

            return editor.getTableCellEditorComponent(table, value, isSelected, row, column);
        }
    }
}

N.B. DatePickerCellEditor от SwingX

Ответ 2

Я пришел к другому решению, так как хотел повторно использовать редакторы по умолчанию... Следующий класс переопределяет getColumnClass для получения другого ответа. Насколько я тестировал, он отлично работает, и я могу использовать setDefaultEditor и так далее. Вы можете заметить, что это можно улучшить, чтобы применить его только к нужным столбцам.

public class JXMultiTypeColumnTable extends JXTable {

private Map<Integer, Class<?>> viewedClassByColumn = new HashMap<Integer, Class<?>>();

public JXMultiTypeColumnTable(Object[][] rowData, Object[] columnNames) {
    super(rowData, columnNames);
}

public JXMultiTypeColumnTable(int numRows, int numColumns) {
    super(numRows, numColumns);
}

public JXMultiTypeColumnTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
    super(dm, cm, sm);
}

public JXMultiTypeColumnTable(TableModel dm, TableColumnModel cm) {
    super(dm, cm);
}

public JXMultiTypeColumnTable(TableModel dm) {
    super(dm);
}

public JXMultiTypeColumnTable() {
}

@Override
public Class<?> getColumnClass(int column) {
    Class<?> recordedClass = this.viewedClassByColumn.get(column);
    if (recordedClass != null) {
        return recordedClass;
    }
    return super.getColumnClass(column);
}

private void recordViewedClass(int row, int column) {
    this.viewedClassByColumn.put(column,
            this.getModel().getValueAt(
            this.convertRowIndexToModel(row), this.convertColumnIndexToModel(column))
            .getClass());
}

@Override
public TableCellRenderer getCellRenderer(int row, int column) {
    this.recordViewedClass(row, column);
    return super.getCellRenderer(row, column);
}

@Override
public TableCellEditor getCellEditor(int row, int column) {
    this.recordViewedClass(row, column);
    return super.getCellEditor(row, column);
}

}

N.B. Можно расширить JTable вместо JXTable.