• 追加された行はこの色です。
  • 削除された行はこの色です。
---
category: swing
folder: MultipleButtonsInTreeNode
title: JTreeのノードにクリック可能なJButtonを複数配置する
tags: [JTree, TreeCellEditor, TreeCellRenderer, JButton, JPanel]
author: aterai
pubdate: 2018-02-12T19:19:08+09:00
description: JTreeのセルエディタとしてクリック可能なJButtonを複数したJPanelを設定します。
image: https://drive.google.com/uc?export=view&id=1av1tLvTqv_249jfJdwdsuhEyB5i3zikC7Q
---
* 概要 [#summary]
`JTree`のセルエディタとしてクリック可能な`JButton`を複数した`JPanel`を設定します。

#download(https://drive.google.com/uc?export=view&id=1av1tLvTqv_249jfJdwdsuhEyB5i3zikC7Q)

* サンプルコード [#sourcecode]
#code(link){{
class ButtonCellEditor extends AbstractCellEditor implements TreeCellEditor {
  private final ButtonPanel panel = new ButtonPanel();
  protected ButtonCellEditor() {
    super();
    panel.b1.addActionListener(e -> {
      System.out.println("b1: " + panel.renderer.getText());
      stopCellEditing();
    });
    panel.b2.addActionListener(e -> {
      System.out.println("b2: " + panel.renderer.getText());
      stopCellEditing();
    });
    panel.b3.addActionListener(e -> {
      System.out.println("b3: " + panel.renderer.getText());
      stopCellEditing();
    });
  }
  @Override public Component getTreeCellEditorComponent(
      JTree tree, Object value, boolean isSelected, boolean expanded,
      boolean leaf, int row) {
    Component c = panel.renderer.getTreeCellRendererComponent(
        tree, value, true, expanded, leaf, row, true);
    return panel.remakePanel(c);
  }
  @Override public Object getCellEditorValue() {
    return panel.renderer.getText();
  }
  @Override public boolean isCellEditable(EventObject e) {
    Object source = e.getSource();
    if (!(source instanceof JTree) || !(e instanceof MouseEvent)) {
      return false;
    }
    JTree tree = (JTree) source;
    Point p = ((MouseEvent) e).getPoint();
    TreePath path = tree.getPathForLocation(p.x, p.y);
    if (Objects.isNull(path)) {
      return false;
    }
    Rectangle r = tree.getPathBounds(path);
    if (Objects.isNull(r)) {
      return false;
    }
    r.width = panel.getButtonAreaWidth();

    if (r.contains(p)) {
      return true;
    }
    return false;
  }
}
}}

* 解説 [#explanation]
上記のサンプルでは、`3`つの`JButton`と`JLabel`を継承する`DefaultTreeCellRenderer`を`FlowLayout`で配置する`JPanel`を`2`つ作成し、それぞれを`JTree`のセルエディタとセルレンダラーとして設定しています。

- セルレンダラーの`JButton`は表示にのみ使用するめ、`ActionListener`などは設定しない
- セルエディタの`JButton`には、`JTree`のノードが編集可能になって自身がクリックされたときに実行する`ActionListener`を設定
-- この`ActionListener`が実行されたあと、`AbstractCellEditor#stopCellEditing()`を実行して`JTree`のノード編集を終了する
-- `JTree`のノード編集を終了しないと、編集中のノードの各ボタンにフォーカスが描画されたり、別ノードのボタンを`2`回クリックしないとそのボタンのイベントが実行できない
- `TreeCellEditor#isCellEditable(...)`をオーバーライドし、マウスで各`JButton`の表示領域がクリックされた場合のみ編集可能に設定
- 編集中のノードの`JButton`のみマウスでクリック可能

* 参考リンク [#reference]
- [[JTreeのセルエディタにJComboBoxなどを配置したJPanelを使用する>Swing/ComboBoxCellEditor]]

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