JPopupMenuに追加したJTextFieldを使用してJMenuItemの表示をフィルタリングする
Total: 161, Today: 1, Yesterday: 1
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をオーバーフローメニューに移動する