概要

JPopupMenuをキー入力で開く場合の表示位置をJTextFieldならキャレット、JListなら選択セル中央となるように調整します。

サンプルコード

class NewspaperStyleList<E extends ListItem> extends JList<E> {
  protected NewspaperStyleList(DefaultListModel<E> model) {
    super(model);
  }

  @Override public void updateUI() {
    setSelectionForeground(null);
    setSelectionBackground(null);
    setCellRenderer(null);
    super.updateUI();
    setLayoutOrientation(JList.HORIZONTAL_WRAP);
    getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    setVisibleRowCount(0);
    setFixedCellWidth(64);
    setFixedCellHeight(64);
    setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    setCellRenderer(new ListItemListCellRenderer<>());
  }

  @Override public Point getPopupLocation(MouseEvent event) {
    if (event == null) {
      int i = getLeadSelectionIndex();
      Rectangle r = getCellBounds(i, i);
      if (r != null) {
        return new Point((int) r.getCenterX(), (int) r.getCenterY());
      }
    }
    return super.getPopupLocation(event);
  }
}
View in GitHub: Java, Kotlin

解説

  • コンポーネントにsetComponentPopupMenu(JPopupMenu)メソッドで設定したJPopupMenuは、たとえばWindows環境ではマウスの右クリックやCONTEXT_MENUキーで開くことが可能
    • CONTEXT_MENUShift+F10キーの入力でJPopupMenuを開く場合、JRootPaneに設定されたpostPopupアクションが実行される
    • このときgetPopupLocation(MouseEvent)JPopupMenuを開く位置が決まるが、戻り値がデフォルトのnullの場合は対象コンポーネントの中央が原点になる
    • getPopupLocation(MouseEvent)メソッドの引数であるMouseEventはキー入力の場合nullになる
  • JTextField
    • キー入力でJPopupMenuを開く場合、JTextFieldの中央ではなくキャレットの下端にJPopupMenuの左上を配置して開くようJTextField#getPopupLocation(MouseEvent)メソッドをオーバーライド
  • JList
    • キー入力でJPopupMenuを開く場合、JListの中央ではなく選択セルの中央にJPopupMenuの左上を配置して開くようJList#getPopupLocation(MouseEvent)メソッドをオーバーライド
    • メモ: Windows 10などのファイルエクスプローラでファイルなどを選択してCONTEXT_MENUキーでポップアップメニューを開く場合、選択セルの中央に右上?を配置して開く仕様になっている?

参考リンク

コメント