Swing/FocusBeforePopup の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/FocusBeforePopup へ行く。
- Swing/FocusBeforePopup の差分を削除
--- category: swing folder: FocusBeforePopup title: JPopupMenuを開く前に対象となるJTextFieldにFocusを移動する tags: [JPopupMenu, JTextField, Focus, JTextComponent] author: aterai pubdate: 2017-11-06T15:23:38+09:00 description: JTextFieldなどに設定したJPopupMenuをマウスの右クリックで開くとき、そのにFocusを移動し文字列を全選択します。 image: https://drive.google.com/uc?id=1DYqevQ-Nj2i5IptiAWC7KPYVKcbmuL9sMA --- * 概要 [#summary] `JTextField`などに設定した`JPopupMenu`をマウスの右クリックで開くとき、その`JTextComponent`に`Focus`を移動し文字列を全選択します。 #download(https://drive.google.com/uc?id=1DYqevQ-Nj2i5IptiAWC7KPYVKcbmuL9sMA) * サンプルコード [#sourcecode] #code(link){{ 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(); protected TextComponentPopupMenu() { super(); add(cutAction); add(copyAction); add(pasteAction); } @Override public void show(Component c, int x, int y) { System.out.println(c.getClass().getName() + ": " + c.getName()); if (c instanceof JTextComponent) { JTextComponent tc = (JTextComponent) c; tc.requestFocusInWindow(); boolean isSelected = tc.getSelectionStart() != tc.getSelectionEnd(); if (tc instanceof JTextField && !tc.isFocusOwner() && !isSelected) { tc.selectAll(); isSelected = true; } cutAction.setEnabled(isSelected); copyAction.setEnabled(isSelected); super.show(c, x, y); } } } }} * 解説 [#explanation] - `Default setComponentPopupMenu` -- `JTextField#setComponentPopupMenu(...)`で`JTextField`に`JPopupMenu`を設定 -- 別の`JTextComponent`にフォーカスがある状態でこの`JTextField`内を右クリックして`JPopupMenu`を表示してもフォーカスは前の`JTextComponent`に残る -- `new DefaultEditorKit.PasteAction()`で生成した貼り込みアクションなどはフォーカスのある`JTextComponent`に対して実行されるので、前の`JTextComponent`に文字列が張り込まれる - `Override JPopupMenu#show(...)` -- `JTextField#setComponentPopupMenu(...)`で`JTextField`に`JPopupMenu`を設定 -- `JPopupMenu#show(...)`をオーバーライドして`JPopupMenu`を開く前に`Component#requestFocusInWindow()`メソッドを実行し、この`JTextField`にフォーカスを移動する --- `PopupMenuListener#popupMenuWillBecomeVisible(...)`、または`MouseListener#mousePressed(...)`をオーバーライドする方法でも構わない -- フォーカス移動と合わせて`JTextField`内を右クリックして`JPopupMenu`を開く場合は内部の文字列を全選択する処理を追加 ---- - `JPopupMenu does not open???` -- 編集可能に設定した`JComboBox`の`JTextField`にマウスクリックでフォーカスを移動しても、他コンポーネントの`JPopupMenu`が開いたままになるバグ(仕様?)があるため、`JTextField#setComponentPopupMenu(...)`で追加した`JPopupMenu`を開くことができない -- [https://bugs.openjdk.java.net/browse/JDK-8044493 JDK-8044493 Clicking on an editable JComboBox leaves JPopupMenus and other menus open - Java Bug System] -- [https://bugs.openjdk.org/browse/JDK-8044493 JDK-8044493 Clicking on an editable JComboBox leaves JPopupMenus and other menus open - Java Bug System] -- [https://explodingpixels.wordpress.com/2008/11/10/prevent-popup-menu-dismissal/ Prevent popup menu dismissal | Exploding Pixels] --- `textField.putClientProperty("doNotCancelPopup", null);`で回避可能だが、エディタをマウスでクリックすると`JComboBox`のドロップダウンリストも閉じるようになる #code{{ JComboBox<String> combo5 = new JComboBox<>(new String[] {"000", "111", "222"}); combo5.setEditable(true); combo5.setComponentPopupMenu(popup2); JTextField textField5 = (JTextField) combo5.getEditor().getEditorComponent(); textField5.putClientProperty("doNotCancelPopup", null); }} - `addMouseListener` -- 編集可能に設定した`JComboBox`の`JTextField`に`MouseListener`を追加し、マウスでクリックされたら一旦すべての`JPopupMenu`を閉じるよう設定 --- ただし、自身の親の`JComboBox`が開いたドロップダウンリストは除外する --- 参考: [[MenuSelectionManagerですべてのJPopupMenuを取得する>Swing/GetAllPopupMenus]] #code{{ JComboBox<String> combo4 = new JComboBox<>(new String[] {"addMouseListener", "111", "222"}); combo4.setEditable(true); JTextField textField4 = (JTextField) combo4.getEditor().getEditorComponent(); textField4.setComponentPopupMenu(popup2); textField4.setName("textField4"); textField4.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { System.out.println("Close all JPopupMenu"); // https://ateraimemo.com/Swing/GetAllPopupMenus.html for (MenuElement m : MenuSelectionManager.defaultManager().getSelectedPath()) { if (combo4.isPopupVisible()) { continue; } else if (m instanceof JPopupMenu) { ((JPopupMenu) m).setVisible(false); } } } }); }} * 参考リンク [#reference] - [[DefaultEditorKitでポップアップメニューからコピー>Swing/DefaultEditorKit]] - [[MenuSelectionManagerですべてのJPopupMenuを取得する>Swing/GetAllPopupMenus]] - [[JTextField内のテキストをすべて選択>Swing/SelectAll]] - [https://bugs.openjdk.java.net/browse/JDK-8044493 JDK-8044493 Clicking on an editable JComboBox leaves JPopupMenus and other menus open - Java Bug System] - [https://bugs.openjdk.org/browse/JDK-8044493 JDK-8044493 Clicking on an editable JComboBox leaves JPopupMenus and other menus open - Java Bug System] * コメント [#comment] #comment #comment