Swing/CellEditorPopupMenu の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/CellEditorPopupMenu へ行く。
- Swing/CellEditorPopupMenu の差分を削除
--- 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: https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTIn7Rc6TI/AAAAAAAAATE/drRaDYiUB1w/s800/CellEditorPopupMenu.png hreflang: href: https://java-swing-tips.blogspot.com/2010/11/jtable-celleditor-popupmenu.html lang: en --- * 概要 [#summary] `JTable`のセルエディタに、`Copy`、`Paste`、`Undo`、`Redo`などを行う`JPopupMenu`を設定します。 #download(https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTIn7Rc6TI/AAAAAAAAATE/drRaDYiUB1w/s800/CellEditorPopupMenu.png) * サンプルコード [#sourcecode] #code(link){{ public static JPopupMenu installTextComponentPopupMenu(final JTextComponent tc) { UndoManager manager = new UndoManager(); Action undoAction = new UndoAction(manager); Action redoAction = new RedoAction(manager); Action cutAction = new DefaultEditorKit.CutAction(); Action copyAction = new DefaultEditorKit.CopyAction(); Action pasteAction = new DefaultEditorKit.PasteAction(); 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(); } class TextComponentPopupMenu extends JPopupMenu { 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(); @Override public void ancestorMoved(AncestorEvent e) {} UndoManager manager = new UndoManager(); Action undoAction = new UndoAction(manager); add(undoAction); @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"); Action redoAction = new RedoAction(manager); add(redoAction); JPopupMenu popup = new JPopupMenu(); popup.add(cutAction); popup.add(copyAction); popup.add(pasteAction); popup.add(deleteAction); popup.addSeparator(); popup.add(undoAction); popup.add(redoAction); tc.addAncestorListener(new AncestorListener() { @Override public void ancestorAdded(AncestorEvent e) { manager.discardAllEdits(); e.getComponent().requestFocusInWindow(); } popup.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuCanceled(PopupMenuEvent e) {} @Override public void ancestorMoved(AncestorEvent e) { /* not needed */ } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { undoAction.setEnabled(true); redoAction.setEnabled(true); } @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"); @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; addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuCanceled(PopupMenuEvent e) { /* not needed */ } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { undoAction.setEnabled(true); redoAction.setEnabled(true); } @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()); } }); } } }} * 解説 [#explanation] 上記のサンプルでは、`JTable`のセルエディタ内の文字列に対して、`Cut`、`Copy`、`Paste`、`Delete`、`Undo`、`Redo`を行うための`JPopupMenu`を設定しています。 ---- - セルエディタとして使用する`JTextField`は、同一インスタンス使い回しているため、別セルでの編集が持ち越されないよう`AncestorListener`を使って表示されるたびに`UndoManager#discardAllEdits()`を呼び出してリセット -- もしくは`DefaultCellEditor#isCellEditable(...)`などをオーバーライドしてリセット #code{{ 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); }} * 参考リンク [#reference] - [https://www.ne.jp/asahi/hishidama/home/tech/java/swing/JTable.html Java Swing「JTable」メモ(Hishidama's Swing-JTable Memo)] -- セルエディタ内だけではなく、行の追加、削除などを`Undo`、`Redo`するサンプルが参考になる * コメント [#comment] #comment #comment