Swing/CellEditorPopupMenu のバックアップの現在との差分(No.19)
- category: swing
folder: CellEditorPopupMenu
title: JTableのセルエディタにJPopupMenuを設定
tags: [JTable, TableCellEditor, UndoManager, JPopupMenu, AncestorListener]
author: aterai
pubdate: 2010-04-26T16:54:26+09:00
description: JTableのセルエディタに、Copy、Paste、Undo、Redoなどを行うJPopupMenuを設定します。
image:
hreflang:
href: https://java-swing-tips.blogspot.com/2010/11/jtable-celleditor-popupmenu.html lang: en
概要
JTable
のセルエディタに、Copy
、Paste
、Undo
、Redo
などを行うJPopupMenu
を設定します。
Screenshot
Advertisement
サンプルコード
#spandel
public static JPopupMenu installTextComponentPopupMenu(final JTextComponent tc) {
#spanend
final UndoManager manager = new UndoManager();
final Action undoAction = new UndoAction(manager);
final Action redoAction = new RedoAction(manager);
final Action cutAction = new DefaultEditorKit.CutAction();
final Action copyAction = new DefaultEditorKit.CopyAction();
final Action pasteAction = new DefaultEditorKit.PasteAction();
final Action deleteAction = new AbstractAction("delete") {
@Override public void actionPerformed(ActionEvent e) {
((JTextComponent) getInvoker()).replaceSelection(null);
}
};
tc.addAncestorListener(new AncestorListener() {
@Override public void ancestorAdded(AncestorEvent e) {
manager.discardAllEdits();
tc.requestFocusInWindow();
}
@Override public void ancestorMoved(AncestorEvent e) {}
@Override public void ancestorRemoved(AncestorEvent e) {}
});
tc.getDocument().addUndoableEditListener(manager);
tc.getActionMap().put("undo", undoAction);
tc.getActionMap().put("redo", redoAction);
InputMap imap = tc.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
imap.put(KeyStroke.getKeyStroke(
KeyEvent.VK_Z, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "undo");
imap.put(KeyStroke.getKeyStroke(
KeyEvent.VK_Y, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "redo");
#spanadd
class TextComponentPopupMenu extends JPopupMenu {
#spanend
protected TextComponentPopupMenu(JTextComponent tc) {
super();
Action cutAction = new DefaultEditorKit.CutAction();
add(cutAction);
Action copyAction = new DefaultEditorKit.CopyAction();
add(copyAction);
Action pasteAction = new DefaultEditorKit.PasteAction();
add(pasteAction);
Action deleteAction = new DeleteAction();
add(deleteAction);
addSeparator();
JPopupMenu popup = new JPopupMenu();
popup.add(cutAction);
popup.add(copyAction);
popup.add(pasteAction);
popup.add(deleteAction);
popup.addSeparator();
popup.add(undoAction);
popup.add(redoAction);
UndoManager manager = new UndoManager();
Action undoAction = new UndoAction(manager);
add(undoAction);
popup.addPopupMenuListener(new PopupMenuListener() {
@Override public void popupMenuCanceled(PopupMenuEvent e) {}
@Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
undoAction.setEnabled(true);
redoAction.setEnabled(true);
}
@Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
JPopupMenu pop = (JPopupMenu) e.getSource();
JTextField field = (JTextField) pop.getInvoker();
boolean flg = field.getSelectedText() != null;
cutAction.setEnabled(flg);
copyAction.setEnabled(flg);
deleteAction.setEnabled(flg);
undoAction.setEnabled(manager.canUndo());
redoAction.setEnabled(manager.canRedo());
}
});
tc.setComponentPopupMenu(popup);
return popup;
Action redoAction = new RedoAction(manager);
add(redoAction);
#spanadd
#spanend
tc.addAncestorListener(new AncestorListener() {
@Override public void ancestorAdded(AncestorEvent e) {
manager.discardAllEdits();
e.getComponent().requestFocusInWindow();
}
#spanadd
#spanend
@Override public void ancestorMoved(AncestorEvent e) {
/* not needed */
}
#spanadd
#spanend
@Override public void ancestorRemoved(AncestorEvent e) {
/* not needed */
}
});
tc.getDocument().addUndoableEditListener(manager);
tc.getActionMap().put("undo", undoAction);
tc.getActionMap().put("redo", redoAction);
InputMap im = tc.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
// Java 10: int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, mask), "undo");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, mask), "redo");
#spanadd
#spanend
addPopupMenuListener(new PopupMenuListener() {
@Override public void popupMenuCanceled(PopupMenuEvent e) {
/* not needed */
}
#spanadd
#spanend
@Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
undoAction.setEnabled(true);
redoAction.setEnabled(true);
}
#spanadd
#spanend
@Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
JTextComponent tc = (JTextComponent) getInvoker();
boolean hasSelectedText = Objects.nonNull(tc.getSelectedText());
cutAction.setEnabled(hasSelectedText);
copyAction.setEnabled(hasSelectedText);
deleteAction.setEnabled(hasSelectedText);
undoAction.setEnabled(manager.canUndo());
redoAction.setEnabled(manager.canRedo());
}
});
}
}
View in GitHub: Java, Kotlin解説
上記のサンプルでは、JTable
のセルエディタ内の文字列に対して、Cut
、Copy
、Paste
、Delete
、Undo
、Redo
を行うためのJPopupMenu
を設定しています。
- セルエディタとして使用する
JTextField
は、同一インスタンス使い回しているため、別セルでの編集が持ち越されないようAncestorListener
を使って表示されるたびにUndoManager#discardAllEdits()
を呼び出してリセット- もしくは、
DefaultCellEditor#isCellEditable(...)
などをオーバーライドしてリセット - もしくは
DefaultCellEditor#isCellEditable(...)
などをオーバーライドしてリセット
- もしくは、
DefaultCellEditor ce = new DefaultCellEditor(new JTextField()) {
@Override public boolean isCellEditable(EventObject e) {
boolean b = super.isCellEditable(e);
if (b) {
manager.discardAllEdits();
}
return b;
}
};
table.setDefaultEditor(Object.class, ce);
参考リンク
- Java Swing「JTable」メモ(Hishidama's Swing-JTable Memo)
- セルエディタ内だけではなく、行の追加、削除などを
Undo
、Redo
するサンプルが参考になる
- セルエディタ内だけではなく、行の追加、削除などを