Summary

JPopupMenuの先頭にJTextFieldを配置し入力された正規表現パターンを使用して、同じくJPopupMenu内に配置されたJMenuItemの表示状態をフィルタリングします。

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, Kotlin

Description

  • JMenu(JMenuが使用するJPopupMenu)に正規表現Patternを入力するためのJTextFieldを挿入
  • JTextFieldの編集をDocumentListenerで取得し、入力された正規表現PatternにマッチするタイトルのJMenuItemを検索する
    • JMenu#getPopupMenu()#getSubElements()JTextFieldを除くMenuElement一覧を取得してJMenuItemのタイトルを調査
  • 表示されるJMenuItemの数が変化するので、JMenu#getPopupMenu()#pack()を実行して親JPopupMenuのサイズを更新
    • pack()後にEventQueue.invokeLater(field::requestFocusInWindow)を実行してJTextField側にフォーカスを戻す

Reference

Comment