I have a table like above. Initially all the cells except button column are not editable. I have created the table using custom TableModel
. My isCellEditable
in custom TableModel
looks like this:
public boolean isCellEditable(int rowIndex, int columnIndex) { //System.out.println("isCellEditable: " + rowIndex + " " + columnIndex); if(getColumnClass(columnIndex) == JButton.class) return true; else return false; }
But when I click on the Edit button of each row a JDialog
will pop up with that row (by constructing a JTable
in this dialog with only one row.) I can update the cell values in this JDialog’s table. and then update them in the respective cells of that row.
I successfully updated the main table’s row after updating here, only if my isCellEditable
return true. But this should not happen. Only when I click then I should be able to change isCellEditable
of the row as Editable and update and then make it uneditable.
I have seen the following post but was unable to implement it.
Advertisement
Answer
Fleshing out my comment to the question:
there’s no need to tweak the editability of the full model: create another model populated by the filtered (column-wise) row of the original, make that other editable and on commit let it write back the changed values to the original
with a bit of code:
public static class ButtonDialogEditor extends AbstractCellEditor implements TableCellEditor { // the columns to present for editing, in model coordinates public final int lastColumn; public final int firstColumn; // the row to present for editing, in model coordinates private int row; private DefaultTableModel model; private JDialog dialog; private boolean committed; private JButton editingComponent; public ButtonDialogEditor(int firstColumn, int lastColumn) { this.firstColumn = firstColumn; this.lastColumn = lastColumn; model = new DefaultTableModel(1, lastColumn - firstColumn + 1); JTable table = new JTable(model); table.putClientProperty("terminateEditOnFocusLost",true); dialog = new JDialog(); dialog.setModal(true); dialog.add(new JScrollPane(table)); dialog.add(new JButton(createOkAction()), BorderLayout.SOUTH); dialog.pack(); editingComponent = new JButton(createShowDialogAction()); } /** * Returns the cell value at column. Note that column * is in the model coordinate system of the source model. */ public Object getValueAt(int column) { return model.getValueAt(0, column - firstColumn); } /** * Returns the row index of the edited row in * model coordinates of the source table. */ public int getModelRow() { return row; } /** * Creates and returns the action used for * the editing component button. * * Implemented to show the modal dialog and fire * editingSotpped/canceled depending on the committed * flag */ private Action createShowDialogAction() { Action action = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { // reset committed committed = false; dialog.setVisible(true); if (committed) { fireEditingStopped(); } else { fireEditingCanceled(); } } }; return action; } /** * Creates and returns the action used for the dialog's * OK button. * * Implemented to hide the dialog and set the * committed flag to true. */ private Action createOkAction() { Action action = new AbstractAction("OK") { @Override public void actionPerformed(ActionEvent e) { dialog.setVisible(false); committed = true; } }; return action; } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { editingComponent.setText(value != null ? value.toString() : ""); prepareDialog(table, row); return editingComponent; } /** * Update internal state to the row to edit. */ private void prepareDialog(JTable table, int row) { this.row = table.convertRowIndexToModel(row); for (int i = firstColumn; i <= lastColumn; i++) { model.setValueAt(table.getModel().getValueAt(this.row, i), 0, i - firstColumn); } } /** * Implemented to return the original value as * given in the */ @Override public Object getCellEditorValue() { return editingComponent.getText(); } } public static class ButtonRenderer implements TableCellRenderer { JButton button = new JButton(); @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { button.setText(value != null ? value.toString() : ""); return button; } } // example usage // source model is not editable except for the button column final DefaultTableModel model = new DefaultTableModel(0, 3) { @Override public boolean isCellEditable(int row, int column) { return column == 0; } }; for (int i = 0; i < 20; i++) { model.addRow(new Object[] {"Edit", i}); } JTable table = new JTable(model); table.getColumnModel().getColumn(0).setCellRenderer(new ButtonRenderer()); final ButtonDialogEditor cellEditor = new ButtonDialogEditor(1, model.getColumnCount() - 1); // custom editor listener which writes back the edited values // to the model on editingStopped. CellEditorListener l = new CellEditorListener() { @Override public void editingStopped(ChangeEvent e) { for (int i = cellEditor.firstColumn; i <= cellEditor.lastColumn; i++) { model.setValueAt(cellEditor.getValueAt(i), cellEditor.getModelRow(), i); } } @Override public void editingCanceled(ChangeEvent e) { // nothing to do } }; cellEditor.addCellEditorListener(l); table.getColumnModel().getColumn(0).setCellEditor( cellEditor);