概要

JButtonのドロップダウンリストで、各アイテムにクリック可能なJButtonを追加しこれを削除します。

スクリーンショット

RemoveButtonInComboItem.png

サンプルコード

class CellButtonsMouseListener extends MouseAdapter {
  @Override public void mouseMoved(MouseEvent e) {
    JList<?> list = (JList<?>) e.getComponent();
    Point pt = e.getPoint();
    int index = list.locationToIndex(pt);
    ButtonsRenderer<?> renderer = (ButtonsRenderer<?>) list.getCellRenderer();
    renderer.rolloverIndex = Objects.nonNull(getButton(list, pt, index)) ? index : -1;
    list.repaint();
  }

  @Override public void mousePressed(MouseEvent e) {
    e.getComponent().repaint();
  }

  @Override public void mouseReleased(MouseEvent e) {
    JList<?> list = (JList<?>) e.getComponent();
    Point pt = e.getPoint();
    int index = list.locationToIndex(pt);
    if (index >= 0) {
      JButton button = getButton(list, pt, index);
      if (Objects.nonNull(button)) {
        button.doClick();
      }
    }
    ((ButtonsRenderer<?>) list.getCellRenderer()).rolloverIndex = -1;
    list.repaint();
  }

  @Override public void mouseExited(MouseEvent e) {
    JList<?> list = (JList<?>) e.getComponent();
    ((ButtonsRenderer<?>) list.getCellRenderer()).rolloverIndex = -1;
  }

  private static <E> JButton getButton(JList<E> list, Point pt, int index) {
    E proto = list.getPrototypeCellValue();
    Component c = list.getCellRenderer().getListCellRendererComponent(
        list, proto, index, false, false);
    Rectangle r = list.getCellBounds(index, index);
    c.setBounds(r);
    // c.doLayout(); // may be needed for other layout managers (eg. FlowLayout)
    pt.translate(-r.x, -r.y);
    return Optional.ofNullable(SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y))
        .filter(JButton.class::isInstance).map(JButton.class::cast).orElse(null);
  }
}
View in GitHub: Java, Kotlin

解説

JComboBoxのドロップダウンリスト(ComboPopup)からJListを取得し、これに上記のようなMouseListenerを追加しています。

  • JListがクリックされた場合、レンダラーから対応するセルに表示されているJButtonを取得してJButton#doClick()メソッドを実行
    Accessible a = getAccessibleContext().getAccessibleChild(0);
    if (a instanceof ComboPopup) {
      ComboPopup pop = (ComboPopup) a;
      JList list = pop.getList();
      CellButtonsMouseListener cbml = new CellButtonsMouseListener();
      list.addMouseListener(cbml);
      list.addMouseMotionListener(cbml);
    }
    
  • 削除ボタンがクリックされてもドロップダウンリスト(ComboPopup)は表示状態のまま残したい
    • MutableComboBoxModel#removeElementAt(index)のあとでJComboBox#showPopup()を実行して開き直す
    • ComboPopupJFrameの外に表示されている(Heavy weight)場合、一旦閉じてから再度開く様子が見えてしまう

参考リンク

コメント