---
category: swing
folder: ComponentPopupMenu
title: JPopupMenuをコンポーネントに追加
tags: [JPopupMenu, JTextComponent, PopupMenuListener, DefaultEditorKit]
author: aterai
pubdate: 2008-03-10T01:39:57+09:00
description: JComponentに右クリックなどでポップアップするJPopupMenuを追加します。
image: https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTKBw4_YtI/AAAAAAAAAVU/J_aFRLSj-VU/s800/ComponentPopupMenu.png
---
* 概要 [#summary]
`JComponent`に右クリックなどでポップアップする`JPopupMenu`を追加します。

#download(https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTKBw4_YtI/AAAAAAAAAVU/J_aFRLSj-VU/s800/ComponentPopupMenu.png)

* サンプルコード [#sourcecode]
#code(link){{
JTextArea textArea = new JTextArea("ComponentPopupMenu Test");
textArea.setComponentPopupMenu(new TextComponentPopupMenu());

class TextComponentPopupMenu extends JPopupMenu {
  private final Action cutAction = new DefaultEditorKit.CutAction();
  private final Action copyAction = new DefaultEditorKit.CopyAction();
  private final Action pasteAction = new DefaultEditorKit.PasteAction();
  private final Action deleteAction;
  private final Action selectAllAction;
  public TextComponentPopupMenu() {
    super();
    add(cutAction);
    add(copyAction);
    add(pasteAction);
    addSeparator();
    add(deleteAction = new AbstractAction("delete") {
      @Override public void actionPerformed(ActionEvent evt) {
        ((JTextComponent) getInvoker()).replaceSelection(null);
      }
    });
    addSeparator();
    add(selectAllAction = new AbstractAction("select all") {
      @Override public void actionPerformed(ActionEvent evt) {
        ((JTextComponent) getInvoker()).selectAll();
      }
    });
    // ActionMap am = textArea.getActionMap();
    // add(cutAction = am.get("cut-to-clipboard"));
    // add(copyAction = am.get("copy-to-clipboard"));
    // add(am.get("paste-from-clipboard"));
    // addSeparator();
    // add(deleteAction = am.get("delete-next"));
    // addSeparator();
    // add(am.get("select-all"));
  }

  @Override public void show(Component c, int x, int y) {
    JTextComponent textArea = (JTextComponent) c;
    boolean flg = textArea.getSelectedText() != null;
    cutAction.setEnabled(flg);
    copyAction.setEnabled(flg);
    deleteAction.setEnabled(flg);
    super.show(c, x, y);
  }
}
}}

* 解説 [#explanation]
上記のサンプルでは、`JTextArea`に`setComponentPopupMenu(JPopupMenu)`メソッドで、ポップアップメニューを追加しています。

- `JDK 1.5`でこのメソッドが追加されたため、各コンポーネントにマウスリスナーを設定して`e.isPopupTrigger()`でポップアップを表示するクリックの判断が不要になった
- ポップアップメニューを表示するときにコンポーネントの状態(例えば`JTable`や`JList`などでの行選択の有無や、テキストが選択されてるかとどうかなどの条件)でメニューが実行可か不可かを変更したい場合は、`JPopupMenu#show(Component, int, int)`メソッドをオーバーライドして使用可能
- このサンプルではテキストが選択されている場合だけカット、コピー、削除メニューが有効になるよう設定

----
- `JPopupMenu#show(Component, int, int)`のオーバーライドではなく、`PopupMenuListener`を使用する方法もある

#code{{
JPopupMenu popup = new JPopupMenu();
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);
  }
};
Action selectAllAction = new AbstractAction("select all") {
  @Override public void actionPerformed(ActionEvent e) {
    JPopupMenu p = (JPopupMenu) e.getSource();
    ((JTextComponent) p.getInvoker()).selectAll();
  }
};
popup.add(cutAction);
popup.add(copyAction);
popup.add(pasteAction);
popup.addSeparator();
popup.add(deleteAction);
popup.addSeparator();
popup.add(selectAllAction);
popup.addPopupMenuListener(new PopupMenuListener() {
  @Override public void popupMenuCanceled(PopupMenuEvent e) {}
  @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {}
  @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
    JPopupMenu p = (JPopupMenu) e.getSource();
    JTextComponent c = (JTextComponent) p.getInvoker();
    boolean flg = c.getSelectedText() != null;
    cutAction.setEnabled(flg);
    copyAction.setEnabled(flg);
    deleteAction.setEnabled(flg);
  }
});
textArea.setComponentPopupMenu(popup);
}}

- `PopupMenuEvent`からはマウスでクリックした位置を取得できない
-- このため、`JTabbedPane`などでどのタブの上でポップアップが表示されるかなどを取得したい場合は`JPopupMenu#show(...)`をオーバーライドする必要がある
-- [[JTabbedPaneでタブを追加削除>Swing/TabbedPane]]

* 参考リンク [#reference]
- [https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/JComponent.html#setComponentPopupMenu-javax.swing.JPopupMenu- JComponent#setComponentPopupMenu(JPopupMenu) (Java Platform SE 8)]
- [[JPopupMenuの取得を親に委譲>Swing/InheritsPopupMenu]]
- [[JTabbedPaneでタブを追加削除>Swing/TabbedPane]]
- [https://bugs.openjdk.java.net/browse/JDK-6675802 Bug ID: 6675802 Regression: heavyweight popups cause SecurityExceptions in applets]
- [https://bugs.openjdk.java.net/browse/JDK-6299213 Bug ID: 6299213 The PopupMenu is not updated if the LAF is changed (incomplete fix of 4962731)]
- [https://bugs.openjdk.org/browse/JDK-6675802 Bug ID: 6675802 Regression: heavyweight popups cause SecurityExceptions in applets]
- [https://bugs.openjdk.org/browse/JDK-6299213 Bug ID: 6299213 The PopupMenu is not updated if the LAF is changed (incomplete fix of 4962731)]

* コメント [#comment]
#comment
#comment