• category: swing folder: BasicComboPopup title: JComboBoxを使ってポップアップメニューをスクロール tags: [BasicComboPopup, JTextPane, JComboBox] author: aterai pubdate: 2005-10-17T19:42:35+09:00 description: JComboBoxを使ってスクロール可能なポップアップメニューを表示します。 image: https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTH_tpIbsI/AAAAAAAAASE/DrHgihVbnn0/s800/BasicComboPopup.png

概要

JComboBoxを使ってスクロール可能なポップアップメニューを表示します。

サンプルコード

class EditorComboPopup extends BasicComboPopup {
  private final JTextComponent textArea;
  private transient MouseAdapter listener;
  protected EditorComboPopup(JTextComponent textArea, JComboBox cb) {
    super(cb);
    this.textArea = textArea;
  }
  @Override protected void installListListeners() {
    super.installListListeners();
    listener = new MouseAdapter() {
      @Override public void mouseClicked(MouseEvent e) {
        hide();
        String str = (String) comboBox.getSelectedItem();
        try {
          Document doc = textArea.getDocument();
          doc.insertString(textArea.getCaretPosition(), str, null);
        } catch (BadLocationException ex) {
          ex.printStackTrace();
        }
      }
    };
    if (Objects.nonNull(list)) {
      list.addMouseListener(listener);
    }
  }
  @Override public void uninstallingUI() {
    if (Objects.nonNull(listener)) {
      list.removeMouseListener(listener);
      listener = null;
    }
    super.uninstallingUI();
  }
  @Override public boolean isFocusable() {
    return true;
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、Shift+Tabでポップアップメニューが表示され、Up, Downキーで移動、EnterJTextPaneのカーソルの後に選択された文字列が入力されます。

JComboBoxのポップアップ部分のUIを表現するBasicComboPopupを利用することで、スクロールバーをもつポップアップメニューを実現しています。

フォーカスを取得して、キー入力で選択を変更できるように、BasicComboPopup#isFocusableメソッドをオーバーライドしています。また、BasicComboPopup#showしたあと、BasicComboPopup#requestFocusInWindowする必要があります。


  • JFrameから、ポップアップメニューがはみ出す(親WindowHeavyWeightWindowになる)場合、カーソルキーなどで、アイテムが移動選択できないバグがある
    • SwingUtilities.getWindowAncestor(popup).toFront();を追加して修正(Ubuntuではうまく動作しない?)
      private void popupMenu(ActionEvent e) {
        Rectangle rect = getMyPopupRect();
        popup.show(jtp, rect.x, rect.y + rect.height);
        EventQueue.invokeLater(new Runnable() {
          @Override public void run() {
            SwingUtilities.getWindowAncestor(popup).toFront();
            popup.requestFocusInWindow();
          }
        });
      }
      
      BasicComboPopup1.png

参考リンク

コメント