Swing/ScrollableListMenu の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/ScrollableListMenu へ行く。
- Swing/ScrollableListMenu の差分を削除
--- category: swing folder: ScrollableListMenu title: JMenuのJPopupMenuにスクロール可能なJListを配置する tags: [JMenu, JPopupMenu, JScrollPane, JList] author: aterai pubdate: 2025-02-24T01:23:27+09:00 description: JMenuのJPopupMenuにJMenuItemではなくスクロールや選択が可能なJListを使用します。 image: https://drive.google.com/uc?id=1fc4sYPBKTHGjJz8rlWWdInMAthSUFFV4 --- * Summary [#summary] `JMenu`の`JPopupMenu`に`JMenuItem`ではなくスクロールや選択が可能な`JList`を使用します。 #download(https://drive.google.com/uc?id=1fc4sYPBKTHGjJz8rlWWdInMAthSUFFV4) * Source Code Examples [#sourcecode] #code(link){{ Font[] fonts = GraphicsEnvironment .getLocalGraphicsEnvironment() .getAllFonts(); DefaultListModel<String> model = new DefaultListModel<>(); Stream.of(fonts) .map(Font::getFontName) .sorted() .forEach(model::addElement); JList<String> list = new PopupList<>(model); JScrollPane scroll = new JScrollPane(list); scroll.setBorder(BorderFactory.createEmptyBorder()); scroll.setViewportBorder(BorderFactory.createEmptyBorder()); JMenu subMenu = new JMenu("Font list"); subMenu.add(scroll); // ... class PopupList<E> extends JList<E> { private transient PopupListMouseListener listener; protected PopupList(ListModel<E> model) { super(model); } @Override public void updateUI() { removeMouseListener(listener); removeMouseMotionListener(listener); super.updateUI(); setFixedCellHeight(20); setSelectionMode(ListSelectionModel.SINGLE_SELECTION); listener = new PopupListMouseListener(); addMouseListener(listener); addMouseMotionListener(listener); Color selectedBg = new Color(0x91_C9_F7); ListCellRenderer<? super E> renderer = getCellRenderer(); setCellRenderer((list, value, index, isSelected, cellHasFocus) -> { Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus); if (c instanceof JComponent && listener.isRolloverIndex(index)) { c.setBackground(selectedBg); c.setForeground(Color.WHITE); } return c; }); } } }} * Explanation [#explanation] - `JMenu#add(scrollPane)`で`JMenu`が使用する`JPopupMenu`の末尾に`JMenuItem`ではなく`JScrollPane`でスクロール可能にした`JList`を配置 - `JMenu#add(...)`で`JMenu`が使用する`JPopupMenu`の末尾に`JMenuItem`ではなく`JScrollPane`でスクロール可能にした`JList`を配置 - `JPopupMenu`に配置された`JList`はスクロール可能だが、マウスカーソルでのロールオーバーやマウスクリックでの選択が不可になるので、以下のような`MouseAdapter`を追加して対応 -- `mouseMoved(...)`が実行されたらロールオーバー表示するリストアイテムのインデックスを記憶し、`JList`に設定した`ListCellRenderer`で背景色などを変更 -- `mouseClicked(...)`が実行されたら`MenuSelectionManager.defaultManager().clearSelectedPath();`を実行することですべてのメニューを閉じる #code{{ class PopupListMouseListener extends MouseAdapter { private int index = -1; public boolean isRolloverIndex(int i) { return this.index == i; } private void setRollover(MouseEvent e) { Point pt = e.getPoint(); Component c = e.getComponent(); if (c instanceof JList) { index = ((JList<?>) c).locationToIndex(pt); c.repaint(); } } @Override public void mouseMoved(MouseEvent e) { setRollover(e); } @Override public void mouseDragged(MouseEvent e) { setRollover(e); } @Override public void mouseClicked(MouseEvent e) { MenuSelectionManager.defaultManager().clearSelectedPath(); } @Override public void mouseExited(MouseEvent e) { index = -1; e.getComponent().repaint(); } } }} * Reference [#reference] - [[JPopupMenuのMenuItemとしてJSpinnerを配置する>Swing/SpinnerMenuItem]] - [[JComboBoxのドロップダウンリストの高さをマウスドラッグで変更する>Swing/DropDownHeightResizing]] * Comment [#comment] #comment #comment