Swing/FocusBeforePopup のバックアップ(No.5)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- 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?export=view&id=1DYqevQ-Nj2i5IptiAWC7KPYVKcbmuL9sMA
概要
JTextField
などに設定したJPopupMenu
をマウスの右クリックで開くとき、そのJTextComponent
にFocus
を移動し文字列を全選択します。
Screenshot
Advertisement
サンプルコード
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);
}
}
}
View in GitHub: Java, Kotlin解説
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
を開くことができない - JDK-8044493 Clicking on an editable JComboBox leaves JPopupMenus and other menus open - Java Bug System
- Prevent popup menu dismissal | Exploding Pixels
textField.putClientProperty("doNotCancelPopup", null);
で回避可能(ただしエディタをマウスでクリックするとJComboBox
のドロップダウンリストも閉じるようになる)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を取得する
- ただし、自身の親の
- 編集可能に設定した
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);
}
}
}
});
参考リンク
- DefaultEditorKitでポップアップメニューからコピー
- MenuSelectionManagerですべてのJPopupMenuを取得する
- JTextField内のテキストをすべて選択
- JDK-8044493 Clicking on an editable JComboBox leaves JPopupMenus and other menus open - Java Bug System