• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:JComboBoxのドロップダウンリストにJButtonを追加
#navi(../)
RIGHT:Posted by [[aterai]] at 2012-07-09
*JComboBoxのドロップダウンリストにJButtonを追加 [#w66d2f92]
JButtonのドロップダウンリストで、各アイテムにクリック可能なJButtonを追加しこれを削除します。

-&jnlp;
-&jar;
-&zip;

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

**サンプルコード [#o70b5054]
#code{{
class CellButtonsMouseListener extends MouseAdapter{
  private int prevIndex = -1;
  private JButton prevButton = null;
  @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);
        if(r!=null) {
          list.repaint(r);
        }
      }
      index = -1;
      prevButton = null;
      return;
    }
    if(index>=0) {
      JButton button = getButton(list, pt, index);
      ButtonsRenderer renderer = (ButtonsRenderer)list.getCellRenderer();
      renderer.button = button;
      if(button != null) {
        button.getModel().setRollover(true);
        renderer.rolloverIndex = index;
        if(!button.equals(prevButton)) {
          Rectangle r = list.getCellBounds(prevIndex, index);
          if(r!=null) {
            list.repaint(r);
          }
        }
      }else{
        renderer.rolloverIndex = -1;
        Rectangle r = null;
        if(prevIndex != index) {
          r = list.getCellBounds(index, index);
        }else if(prevIndex>=0 && prevButton!=null) {
          r = list.getCellBounds(prevIndex, prevIndex);
        }
        if(r!=null) {
          list.repaint(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(button != null) {
        ButtonsRenderer renderer = (ButtonsRenderer)list.getCellRenderer();
        renderer.button = button;
        list.repaint(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(button != null) {
        ButtonsRenderer renderer = (ButtonsRenderer)list.getCellRenderer();
        renderer.button = null;
        button.doClick();
        Rectangle r = list.getCellBounds(index, index);
        if(r!=null) {
          list.repaint(r);
        }
      }
    }
  }
  @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);
    pt.translate(0,-r.y);
    Component b = SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y);
    if(b instanceof JButton) {
      return (JButton)b;
    }else{
      return null;
    }
  }
}
}}

**解説 [#sc8b8fec]
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)、一旦閉じたあとで再度開かれるように見える

//**参考リンク
**コメント [#h9cd9631]
#comment