I would like my JTable
to use different cell editors for different cells in a single column. Think of a two-column label-value table like:
Name | Value
--------------+--------------------------------
Identifier 开发者_StackOverflow | ST33442 (string editor)
Purchase Date | 7/7/10 (custom calendar editor)
Status | Broken (combo editor)
How can I build the editor dynamically? Something like a TableCellEditorFactory
would be perfect.
You've got to implement your own cell editor and assign it to the column. You should probably do the same with a cell renderer (so for instance booleans will be rendered as a check box instead of "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
is from SwingX
I come to another solution, since I wanted to reuse default editors… The following class redefines the getColumnClass to have a different answer. As far as I've tested, it works fine, and I can use setDefaultEditor and so on. You can notice that it's possible to enhance this behavior to apply it only on desired columns.
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. It is possible to extend JTable
instead of JXTable
.
精彩评论