JPopupMenuに追加したJTextFieldを使用してJMenuItemの表示をフィルタリングする
Total: 11
, Today: 11
, Yesterday: 0
Posted by aterai at
Last-modified:
Summary
JPopupMenu
の先頭にJTextField
を配置し入力された正規表現パターンを使用して、同じくJPopupMenu
内に配置されたJMenuItem
の表示状態をフィルタリングします。
Screenshot

Advertisement
Source Code Examples
private static JMenu makeRecentMenu() {
JMenu menu = new JMenu("Recent Files");
JTextField field = new JTextField(20);
menu.add(field);
field.getDocument().addDocumentListener(new DocumentListener() {
@Override public void insertUpdate(DocumentEvent e) {
filter(menu, field);
}
@Override public void removeUpdate(DocumentEvent e) {
filter(menu, field);
}
@Override public void changedUpdate(DocumentEvent e) {
/* not needed */
}
});
menu.add("aa001.txt");
menu.add("aa002.log");
menu.add("aabb33.txt");
menu.add("abc4.md");
menu.add("b5.markdown");
menu.add("ccc6.txt");
return menu;
}
private static Pattern getPattern(JTextField field) {
String regex = field.getText();
Pattern pattern = null;
if (Objects.nonNull(regex) && !regex.isEmpty()) {
try {
pattern = Pattern.compile(regex);
} catch (PatternSyntaxException ex) {
UIManager.getLookAndFeel().provideErrorFeedback(field);
}
}
return pattern;
}
private static void filter(JMenu menu, JTextField field) {
Pattern ptn = getPattern(field);
Stream.of(menu.getPopupMenu().getSubElements())
.filter(JMenuItem.class::isInstance)
.map(JMenuItem.class::cast)
.forEach(mi ->
mi.setVisible(ptn == null || ptn.matcher(mi.getText()).find()));
menu.getPopupMenu().pack();
EventQueue.invokeLater(field::requestFocusInWindow);
}
View in GitHub: Java, KotlinDescription
JMenu
(JMenu
が使用するJPopupMenu
)に正規表現Pattern
を入力するためのJTextField
を挿入- JPopupMenuのMenuItemとしてJSpinnerを配置するのように
JMenuItem
の子要素としてJSpinner
ではなくJTextField
を使用するとJTextField
にフォーカス移動不可となって編集できない? → 調査中
- JPopupMenuのMenuItemとしてJSpinnerを配置するのように
JTextField
の編集をDocumentListener
で取得し、入力された正規表現Pattern
にマッチするタイトルのJMenuItem
を検索するJMenu#getPopupMenu()#getSubElements()
でJTextField
を除くMenuElement
一覧を取得してJMenuItem
のタイトルを調査- マッチする場合は
JMenuItem#setVisible(true)
で可視化、それ以外をJMenuItem#setVisible(false)
で非表示化 - JMenuBarからあふれたJMenuをオーバーフローメニューに移動するのように
JMenuItem
を移動(追加、削除)する必要はないので、JMenuItem#setVisible(...)
での表示・非表示の切り替えでフィルタリングを実行している
- マッチする場合は
- 表示される
JMenuItem
の数が変化するので、JMenu#getPopupMenu()#pack()
を実行して親JPopupMenu
のサイズを更新pack()
後にEventQueue.invokeLater(field::requestFocusInWindow)
を実行してJTextField
側にフォーカスを戻す
Reference
- JListのアイテムをフィルタリングして表示
- JPopupMenuに追加したJSliderの表示・非表示をチェックボックスで切り替える
- JPopupMenuのMenuItemとしてJSpinnerを配置する
- JMenuBarからあふれたJMenuをオーバーフローメニューに移動する