• category: swing folder: DropDownHeightResizing title: JComboBoxのドロップダウンリストの高さをマウスドラッグで変更する tags: [JComboBox, JList, JPopupMenu] author: aterai pubdate: 2022-06-20T00:37:46+09:00 description: JComboBoxのドロップダウンリス下部にドラッグ可能なアイコンを追加し、その高さをマウスドラッグで変更します。 description: JComboBoxのドロップダウンリスト下部にドラッグ可能なアイコンを追加し、その高さをマウスドラッグで変更します。 image: https://drive.google.com/uc?id=1UN09ThQIcw2H8XpxI6ZpY2HOzFytr1-J hreflang:
       href: https://java-swing-tips.blogspot.com/2022/06/change-height-of-drop-down-list-of.html
       lang: en

概要

JComboBoxのドロップダウンリス下部にドラッグ可能なアイコンを追加し、その高さをマウスドラッグで変更します。 JComboBoxのドロップダウンリスト下部にドラッグ可能なアイコンを追加し、その高さをマウスドラッグで変更します。

サンプルコード

#spanadd
JPopupMenu popup = new JPopupMenu();
#spanend
#spanadd
popup.setBorder(BorderFactory.createEmptyBorder());
#spanend
#spanadd
popup.setPopupSize(240, 120);
#spanend
#spanadd

#spanend
JLabel bottom = new JLabel("", new DotIcon(), SwingConstants.CENTER);
#spandel
MouseInputListener rwl = new ResizeWindowListener();
#spanend
#spanadd
MouseInputListener rwl = new ResizeWindowListener(popup);
#spanend
bottom.addMouseListener(rwl);
bottom.addMouseMotionListener(rwl);
bottom.setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
bottom.setOpaque(true);
bottom.setBackground(new Color(0xE0_E0_E0));
bottom.setFocusable(false);

JPanel resizePanel = new JPanel(new BorderLayout());
resizePanel.add(scroll);
resizePanel.add(bottom, BorderLayout.SOUTH);
resizePanel.add(Box.createHorizontalStrut(240), BorderLayout.NORTH);
resizePanel.setBorder(BorderFactory.createLineBorder(new Color(0x64_64_64)));

JPopupMenu popup = new JPopupMenu();
popup.add(resizePanel);
View in GitHub: Java, Kotlin

解説

  • JPopupMenu
    • JPopupMenu内にJMenuItemではなくBorderLayoutを設定したJPanelをひとつ配置
      • このJPanelBorderLayout.CENTERJListBorderLayout.SOUTHに自身の親フレームの高さのみリサイズ可能にするMouseInputListenerを設定したJLabelを追加
#spandel
class ResizeWindowListener extends MouseInputAdapter {
#spanend
#spanadd
class ResizePopupMenuListener extends MouseInputAdapter {
#spanend
  private final Rectangle rect = new Rectangle();
  private final Point startPt = new Point();
  private final Dimension startDim = new Dimension();

  @Override public void mousePressed(MouseEvent e) {
    Window w = SwingUtilities.getWindowAncestor(e.getComponent());
    if (w != null) {
      rect.setSize(w.getSize());
    }
    Container popup = SwingUtilities.getAncestorOfClass(
        JPopupMenu.class, e.getComponent());
    rect.setSize(popup.getSize());
    startDim.setSize(popup.getSize());
    startPt.setLocation(e.getComponent().getLocationOnScreen());
  }

  @Override public void mouseDragged(MouseEvent e) {
    Window w = SwingUtilities.getWindowAncestor(e.getComponent());
    if (!rect.isEmpty() && w != null) {
      rect.height += e.getY();
      w.setSize(rect.width, rect.height);
    rect.height = startDim.height + e.getLocationOnScreen().y - startPt.y;
    Container c = SwingUtilities.getAncestorOfClass(
        JPopupMenu.class, e.getComponent());
    if (c instanceof JPopupMenu) {
      JPopupMenu popup = (JPopupMenu) c;
      popup.setPreferredSize(rect.getSize());
      Window w = SwingUtilities.getWindowAncestor(popup);
      if (w != null && w.getType() == Window.Type.POPUP) {
        // Popup$HeavyWeightWindow
        w.setSize(rect.width, rect.height);
      } else {
        // Popup$LightWeightWindow
        popup.pack();
      }
    }
  }
}
  • JComboBox
    • JComboBox本来のドロップダウンリストはJComboBox.setMaximumRowCount(1)で高さ最小に設定し、PopupMenuListener#popupMenuWillBecomeVisible(...)で上記のJPopupMenuを手前に重ねて表示
    • 手前に表示するJPopupMenuInvokerJComboBoxではなくnullに設定しているのでSwingUtilities.getWindowAncestor(JLabel)JPopupMenuの親フレームが取得可能
      • InvokerJComboBoxに設定するとJComboBoxの親フレームが返ってきてしまう
    • InvokernullなのでJComboBoxの親フレームをクリックしたりリサイズしてもJPopupMenuは自動的に非表示にはならない
      • このサンプルではその親フレームにComponentListenerなどを追加してJPopupMenuを非表示に変更している
    • JComboBox本来のドロップダウンリストはJComboBox.setMaximumRowCount(1)で高さ最小、JComboBox#getPreferredSize()をオーバーライドして幅が上記のJPopupMenu以下になるよう設定し、PopupMenuListener#popupMenuWillBecomeVisible(...)JPopupMenuを手前に重ねて表示
    • 手前に表示するJPopupMenuInvokerJComboBoxではなくnullに設定しているのでSwingUtilities.getWindowAncestor(JLabel)JPopupMenuの親フレームが取得可能
      • InvokerJComboBoxに設定するとJComboBoxの親フレームが返ってきてしまう
    • InvokernullなのでJComboBoxの親フレームをクリックしたりリサイズしてもJPopupMenuは自動的に非表示にはならない
      • このサンプルではその親フレームにComponentListenerなどを追加してJPopupMenuを非表示に変更している
    • InvokerJComboBoxに設定
      • JPopupMenuが親フレーム領域内に収まってlight weight popup(JPopupMenu#getTopLevelAncestor()JComboBoxの親フレームが返ってくる)になる場合はJPopupMenu#setPreferredSize(...) + JPopupMenu#pack()でリサイズ
      • JPopupMenuが親フレーム領域外に高さが拡大されてheavy weight popup(JPopupMenu#getTopLevelAncestor()で共用のJWindowが返ってくる)になる場合はJPopupMenu#setPreferredSize(...) + JWindow#setSize(...)でリサイズ
  • JList
    • 手前に表示するJPopupMenuに追加したJListのアイテム選択とJComboBoxのドロップダウンリストの選択状態をItemListenerを追加して同期
    • JListMouseListenerを追加してダブルクリックでJComboBoxの選択状態更新とJPopupMenuの非表示化を実行
    • GraphicsEnvironment#getAllFonts()で取得したフォント名を一覧表示

参考リンク

コメント