• 追加された行はこの色です。
  • 削除された行はこの色です。
---
category: swing
folder: RemoveButtonInComboItem
title: JComboBoxのドロップダウンリストに追加したJButtonで項目を削除する
tags: [JComboBox, JButton, JList, BasicComboPopup, ListCellRenderer, MouseListener]
author: aterai
pubdate: 2012-07-09T12:02:11+09:00
description: JButtonのドロップダウンリストで、各アイテムにクリック可能なJButtonを追加しこれを削除します。
image: https://lh6.googleusercontent.com/-x9uTOO9fSds/T_pElwy8GBI/AAAAAAAABPM/Jx30phjG3bM/s800/RemoveButtonInComboItem.png
hreflang:
    href: http://java-swing-tips.blogspot.com/2012/10/delete-button-in-jcombobox-popup-menu.html
    lang: en
---
* 概要 [#summary]
`JButton`のドロップダウンリストで、各アイテムにクリック可能な`JButton`を追加しこれを削除します。

#download(https://lh6.googleusercontent.com/-x9uTOO9fSds/T_pElwy8GBI/AAAAAAAABPM/Jx30phjG3bM/s800/RemoveButtonInComboItem.png)

* サンプルコード [#sourcecode]
#code(link){{
class CellButtonsMouseListener extends MouseAdapter {
  private int prevIndex = -1;
  private JButton prevButton;
  private static void listRepaint(JList list, Rectangle rect) {
    if (Objects.nonNull(rect)) {
      list.repaint(rect);
    }
  }
  @Override public void mouseMoved(MouseEvent e) {
    JList list = (JList) e.getComponent();
    Point pt = e.getPoint();
    int index = list.locationToIndex(pt);
    if (!list.getCellBounds(index, index).contains(pt)) {
      if (prevIndex >= 0) {
        Rectangle r = list.getCellBounds(prevIndex, prevIndex);
        listRepaint(list, r);
      }
      index = -1;
      prevButton = null;
      return;
    }
    if (index >= 0) {
      JButton button = getButton(list, pt, index);
      ButtonsRenderer renderer = (ButtonsRenderer) list.getCellRenderer();
      if (Objects.nonNull(button)) {
        renderer.rolloverIndex = index;
        if (!button.equals(prevButton)) {
          Rectangle r = list.getCellBounds(prevIndex, index);
          listRepaint(list, r);
        }
      } else {
        renderer.rolloverIndex = -1;
        Rectangle r = null;
        if (prevIndex == index) {
          if (prevIndex >= 0 && Objects.nonNull(prevButton)) {
            r = list.getCellBounds(prevIndex, prevIndex);
          }
        } else {
          r = list.getCellBounds(index, index);
        }
        listRepaint(list, r);
        prevIndex = -1;
      }
      prevButton = button;
    }
    prevIndex = index;
  }
  @Override public void mousePressed(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)) {
        listRepaint(list, list.getCellBounds(index, index));
      }
    }
  }
  @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();
        Rectangle r = list.getCellBounds(index, index);
        listRepaint(list, r);
      }
    }
  }
  @Override public void mouseExited(MouseEvent e) {
    JList list = (JList) e.getComponent();
    ButtonsRenderer renderer = (ButtonsRenderer) list.getCellRenderer();
    renderer.rolloverIndex = -1;
  }
  @SuppressWarnings("unchecked")
  private static JButton getButton(JList list, Point pt, int index) {
    Container c = (Container) list.getCellRenderer().getListCellRendererComponent(
        list, "", index, false, false);
    Rectangle r = list.getCellBounds(index, index);
    c.setBounds(r);
    //c.doLayout(); //may be needed for mone LayoutManager
    pt.translate(-r.x, -r.y);
    Component b = SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y);
    if (b instanceof JButton) {
      return (JButton) b;
    } else {
      return null;
    }
  }
}
}}

* 解説 [#explanation]
`JComboBox`のドロップダウンリスト(`BasicComboPopup`)から`JList`を取得し、これに上記のような`MouseListener`を追加しています。この`JList`がクリックされた場合、レンダラーから対応するセルに表示されている`JButton`を取得し、`button.doClick()`を呼び出します。

#code{{
Accessible a = getAccessibleContext().getAccessibleChild(0);
if (a instanceof BasicComboPopup) {
  BasicComboPopup pop = (BasicComboPopup) a;
  JList list = pop.getList();
  CellButtonsMouseListener cbml = new CellButtonsMouseListener();
  list.addMouseListener(cbml);
  list.addMouseMotionListener(cbml);
}
}}

- 削除ボタンがクリックされてもドロップダウンリストは表示状態のまま残るように、`MutableComboBoxModel#removeElementAt(index);`のあとで`comboBox.showPopup();`を実行
- `BasicComboPopup`が、フレーム外に表示されている場合(`Heavy weight`)、一旦閉じたあとで再度開かれるように見える
- 削除ボタンがクリックされてもドロップダウンリスト(`BasicComboPopup`)は表示状態のまま残したい
-- `MutableComboBoxModel#removeElementAt(index);`のあとで`comboBox.showPopup();`を実行して開き直す
-- `BasicComboPopup`が`JFrame`の外に表示されている(`Heavy weight`)場合、一旦閉じてから再度開く様子が見えてしまう

* 参考リンク [#reference]
- [[JListのセル内にJButtonを配置する>Swing/ButtonsInListCell]]

* コメント [#comment]
#comment
#comment