• 追加された行はこの色です。
  • 削除された行はこの色です。
---
category: swing
folder: ButtonsInListCell
title: JListのセル内にJButtonを配置する
tags: [JList, JButton, ListCellRenderer]
author: aterai
pubdate: 2011-10-03T14:43:12+09:00
description: JListのセル内に複数のJButtonを配置します。
image: https://lh3.googleusercontent.com/-j4_Xv9F17Jc/TolDAZSkQUI/AAAAAAAABDU/GK_sK9k5aJE/s800/ButtonsInListCell.png
---
* 概要 [#summary]
`JList`のセル内に複数の`JButton`を配置します。

#download(https://lh3.googleusercontent.com/-j4_Xv9F17Jc/TolDAZSkQUI/AAAAAAAABDU/GK_sK9k5aJE/s800/ButtonsInListCell.png)

* サンプルコード [#sourcecode]
#code(link){{
class ButtonsRenderer<E> extends JPanel implements ListCellRenderer<E> {
  private static final Color EVEN_COLOR = new Color(230, 255, 230);
  private final JTextArea textArea = new JTextArea();
  private final JButton deleteButton = new JButton(new AbstractAction("delete") {
    @Override public void actionPerformed(ActionEvent e) {
      if (model.getSize() > 1) {
        model.remove(index);
      }
    }
  });
  private final JButton copyButton = new JButton(new AbstractAction("copy") {
    @Override public void actionPerformed(ActionEvent e) {
      model.add(index, model.get(index));
    }
  });
  private final DefaultListModel<E> model;
  private int index;
  public int pressedIndex  = -1;
  public int rolloverIndex = -1;
  public JButton button;
  protected static final Color EVEN_COLOR = new Color(0xE6_FF_E6);
  protected final JTextArea textArea = new JTextArea();
  protected final JButton deleteButton = new JButton("delete");
  protected final JButton copyButton = new JButton("copy");
  protected final List<JButton> buttons = Arrays.asList(deleteButton, copyButton);
  protected final DefaultListModel<E> model;
  protected int targetIndex;
  protected int pressedIndex = -1;
  protected int rolloverIndex = -1;
  protected JButton button;

  protected ButtonsRenderer(DefaultListModel<E> model) {
    super(new BorderLayout());
    super(new BorderLayout()); // *1
    this.model = model;
    setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 0));
    setOpaque(true);
    textArea.setLineWrap(true);
    textArea.setOpaque(false);
    add(textArea);

    deleteButton.addActionListener(e -> {
      boolean isMoreThanOneItem = model.getSize() > 1;
      if (isMoreThanOneItem) {
        model.remove(targetIndex);
      }
    });
    copyButton.addActionListener(e -> model.add(targetIndex, model.get(targetIndex)));

    Box box = Box.createHorizontalBox();
    for (JButton b : Arrays.asList(deleteButton, copyButton)) {
    buttons.forEach(b -> {
      b.setFocusable(false);
      b.setRolloverEnabled(false);
      box.add(b);
      box.add(Box.createHorizontalStrut(5));
    }
    });
    add(box, BorderLayout.EAST);
  }

  @Override public Dimension getPreferredSize() {
    Dimension d = super.getPreferredSize();
    d.width = 0; // VerticalScrollBar as needed
    return d;
  }

  @Override public Component getListCellRendererComponent(
      JList<? extends E> list, E value, int index,
      boolean isSelected, boolean cellHasFocus) {
    textArea.setText(Objects.toString(value, ""));
    this.index = index;
    this.targetIndex = index;
    if (isSelected) {
      setBackground(list.getSelectionBackground());
      textArea.setForeground(list.getSelectionForeground());
    } else {
      setBackground(index % 2 == 0 ? EVEN_COLOR : list.getBackground());
      textArea.setForeground(list.getForeground());
    }
    resetButtonStatus();
    buttons.forEach(ButtonsRenderer::resetButtonStatus);
    if (Objects.nonNull(button)) {
      if (index == pressedIndex) {
        button.getModel().setSelected(true);
        button.getModel().setArmed(true);
        button.getModel().setPressed(true);
      } else if (index == rolloverIndex) {
        button.getModel().setRollover(true);
      }
    }
    return this;
  }
  private void resetButtonStatus() {
    for (JButton b : Arrays.asList(deleteButton, copyButton)) {
      ButtonModel m = b.getModel();
      m.setRollover(false);
      m.setArmed(false);
      m.setPressed(false);
      m.setSelected(false);
    }

  private static void resetButtonStatus(AbstractButton button) {
    ButtonModel model = button.getModel();
    model.setRollover(false);
    model.setArmed(false);
    model.setPressed(false);
    model.setSelected(false);
  }
}
}}

* 解説 [#explanation]
上記のサンプルでは、`JList`のセルに`2`つの`JButton`を配置する`ListCellRenderer`を設定しています。
`JButton`のクリックイベントは、`JList`に追加したマウスリスナーで`SwingUtilities.getDeepestComponentAt(...)`を使用して対象の`JButton`を取得し、`JButton#doClick()`を呼び出すようになっています。
`JButton`のクリックイベントは`JList`本体に追加したマウスリスナーで`SwingUtilities.getDeepestComponentAt(...)`を使用して`ListCellRenderer`から対象の`JButton`を取得し、`JButton#doClick()`を呼び出しています。

* 参考リンク [#reference]
- [[JTableのセルに複数のJButtonを配置する>Swing/MultipleButtonsInTableCell]]

* コメント [#comment]
#comment
- ダミーの`view, edit`ボタンを実際に動作する行の`delete, copy`ボタンに変更(ソースを修正したのは2011年10月、スクリーンショットは未変更)。 -- &user(aterai); &new{2013-11-20 (水) 16:13:40};
- サンプルの動作未定義だった`view, edit`ボタンを実際に動作する現在行の`delete, copy`ボタンに変更。 -- &user(aterai); &new{2013-11-20 (水) 16:13:40};
- `VerticalScrollBar`が表示されると、セルの幅が縮むように変更。 -- &user(aterai); &new{2016-04-19 (火) 16:13:40};

#comment