Swing/UndoableEditTable のバックアップ(No.2)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/UndoableEditTable へ行く。
- 1 (2025-12-15 (月) 01:02:26)
- 2 (2025-12-15 (月) 01:02:56)
- category: swing folder: UndoableEditTable title: JTableのセル編集をUndo可能にする title-en: Making JTable cell edits undoable tags: [JTable, UndoManager, UndoableEdit] author: aterai pubdate: 2025-12-15T00:58:29+09:00 description: JTableのCellEditorで実行したセル値の編集をキー入力でUndo、Redo可能に設定します。 summary-jp: JTableのCellEditorで実行したセル値の編集をキー入力でUndo、Redo可能に設定します。 summary-en: Enables undo and redo of cell value edits performed in a JTable's CellEditor via keyboard input. image: https://drive.google.com/uc?id=1W7lnyGT5xYgJw3RT7SEFfPbguGLiB-Ny
Summary
JTableのCellEditorで実行したセル値の編集をキー入力でUndo、Redo可能に設定します。
Screenshot

Advertisement
Source Code Examples
class PropertyTable extends JTable {
private static final int TARGET_COLUMN = 1;
private Class<?> editingClass;
private final UndoManager undoManager = new UndoManager();
protected PropertyTable(TableModel model) {
super(model);
initUndoActions();
}
private void initUndoActions() {
String undo = "undo";
String redo = "redo";
ActionMap am = getActionMap();
am.put(undo, new UndoAction());
am.put(redo, new RedoAction());
InputMap im = getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(KeyStroke.getKeyStroke("ctrl Z"), undo);
im.put(KeyStroke.getKeyStroke("ctrl shift Z"), redo);
im.put(KeyStroke.getKeyStroke("ctrl Y"), redo);
}
@Override public void setValueAt(Object newValue, int row, int column) {
if (isEditing()) {
int mr = convertRowIndexToModel(row);
int mc = convertColumnIndexToModel(column);
Object oldValue = getValueAt(mr, mc);
if (!Objects.equals(oldValue, newValue)) {
TableModel m = getModel();
undoManager.addEdit(new UndoableCellEdit(m, mr, mc, oldValue, newValue));
}
}
super.setValueAt(newValue, row, column);
}
private class UndoAction extends AbstractAction {
private UndoAction() {
super("undo");
}
@Override public void actionPerformed(ActionEvent e) {
try {
undoManager.undo();
} catch (CannotUndoException ex) {
UIManager.getLookAndFeel().provideErrorFeedback(
(Component) e.getSource());
}
}
}
private class RedoAction extends AbstractAction {
private RedoAction() {
super("redo");
}
@Override public void actionPerformed(ActionEvent e) {
try {
undoManager.redo();
} catch (CannotRedoException ex) {
UIManager.getLookAndFeel().provideErrorFeedback(
(Component) e.getSource());
}
}
}
// ...
}
View in GitHub: Java, KotlinDescription
JTable#setValueAt(...)をオーバーライドしてセル値が現在のセル値と異なる場合は以下のようなAbstractUndoableEditを実装するUndoableCellEditを作成し、UndoManager#addEdit(...)で追加- `UndoManager#undo()`を実行するアクションを`JTable`の`ActionMap`に追加し、KBD{Ctrl+Z}キー入力でその`Undo`アクションを実行するよう`InputMap`に追加 - `UndoManager#redo()`を実行するアクションも同様に`JTable`の`ActionMap`に追加し、KBD{Ctrl+Y}、またはKBD{Ctrl+Shift+Z}キー入力でその`Redo`アクションを実行するよう`InputMap`に追加
class UndoableCellEdit extends AbstractUndoableEdit {
private final TableModel model;
private final int row;
private final int column;
private final Object oldValue;
private final Object newValue;
protected UndoableCellEdit(
TableModel m, int row, int col, Object oldVal, Object newVal) {
super();
this.model = m;
this.row = row;
this.column = col;
this.oldValue = oldVal;
this.newValue = newVal;
}
@Override public void undo() {
super.undo();
model.setValueAt(oldValue, row, column);
}
@Override public void redo() {
super.redo();
model.setValueAt(newValue, row, column);
}
}