---
category: swing
folder: TreeNodeProgressBar
title: JTreeのノードにJProgressBarを表示する
tags: [JTree, JProgressBar, DefaultTreeCellRenderer, SwingWorker, ExecutorService]
author: aterai
pubdate: 2013-12-23T01:15:16+09:00
description: JTreeのノードにJProgressBarを表示するTreeCellRendererを設定します。
image: https://lh4.googleusercontent.com/-SBg5NOTGinM/UrcLHfPzXVI/AAAAAAAAB84/HD0k-sWiJGo/s800/TreeNodeProgressBar.png
---
* 概要 [#summary]
`JTree`のノードに`JProgressBar`を表示する`TreeCellRenderer`を設定します。

#download(https://lh4.googleusercontent.com/-SBg5NOTGinM/UrcLHfPzXVI/AAAAAAAAB84/HD0k-sWiJGo/s800/TreeNodeProgressBar.png)

* サンプルコード [#sourcecode]
#code(link){{
class ProgressBarRenderer extends DefaultTreeCellRenderer {
  private int nodeWidth = 100;
  private static int barHeight = 4;
  private final JProgressBar b = new JProgressBar(0, 100) {
  // protected int nodeWidth = 100;
  protected static final int BAR_HEIGHT = 4;
  private final JProgressBar progress = new JProgressBar() {
    @Override public Dimension getPreferredSize() {
      Dimension d = super.getPreferredSize();
      d.height = barHeight;
      d.width  = nodeWidth;
      // d.setSize(nodeWidth, BAR_HEIGHT);
      d.height = BAR_HEIGHT;
      return d;
    }

    @Override public void updateUI() {
      super.updateUI();
      setUI(new BasicProgressBarUI());
      setStringPainted(true);
      setString("");
      setOpaque(false);
      setBorder(BorderFactory.createEmptyBorder());
    }
  };
  private final JPanel p = new JPanel(new BorderLayout());
  private final Container renderer = new JPanel(new BorderLayout()) {
    @Override public void updateUI() {
      super.updateUI();
      setOpaque(false);
    }
  };

  public ProgressBarRenderer() {
    super();
    b.setOpaque(false);
    p.setOpaque(false);
    b.setStringPainted(true);
    b.setString("");
    b.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
  }

  @Override public Component getTreeCellRendererComponent(
      JTree tree, Object value, boolean selected, boolean expanded,
      boolean leaf, int row, boolean hasFocus) {
    Component c = super.getTreeCellRendererComponent(
        tree, value, selected, expanded, leaf, row, hasFocus);
    Object o = ((DefaultMutableTreeNode) value).getUserObject();
    JComponent c = (JComponent) super.getTreeCellRendererComponent(
        tree, value, selected, expanded, leaf, row, hasFocus);
    if (!(o instanceof ProgressObject)) {
      return c;
    }
    ProgressObject n = (ProgressObject) o;
    int i = n.getValue();
    b.setValue(i);
    if (o instanceof ProgressObject) {
      ProgressObject n = (ProgressObject) o;
      int i = n.getValue();
      progress.setValue(i);

    FontMetrics metrics = c.getFontMetrics(c.getFont());
    int ww = getX() + getIcon().getIconWidth() + getIconTextGap()
      + metrics.stringWidth(n.title);
    nodeWidth = ww;
      // int titleWidth = c.getFontMetrics(c.getFont()).stringWidth(n.getTitle());
      // int ww = getX() + getIcon().getIconWidth() + getIconTextGap() + titleWidth;
      // nodeWidth = ww;

    p.removeAll();
    p.add(c);
    p.add(i < 100 ? b : Box.createVerticalStrut(barHeight), BorderLayout.SOUTH);
    return p;
      renderer.removeAll();
      renderer.add(c);
      if (i < progress.getMaximum()) {
        renderer.add(progress, BorderLayout.SOUTH);
      }
      c = renderer;
    }
    return c;
  }

  @Override public Dimension getPreferredSize() {
    Dimension d = super.getPreferredSize();
    d.height = 18;
    return d;
  }
}
}}

* 解説 [#explanation]
上記のサンプルでは、タスクが実行中の場合はノードの幅(アイコンと文字列の合計)と同じサイズの`JProgressBar`を配置する`TreeCellRenderer`を作成し、これを`JTree#setCellRenderer(...)`で設定しています。

- スタートボタンを押すと`JButton`を選択不可に設定し、`SwingWorker`を起動して葉以外のノードをすべて捜査
- スタートボタンを押すとその`JButton`を選択不可に設定し、`SwingWorker`を起動して葉以外のノードをすべて捜査
- 取得した各ノードで`SwingWorker`を起動し、進捗を`JProgressBar`を配置した`TreeCellRenderer`で表示
-- ダミータスクが終了するとそのノードを展開
- すべてのノードのタスクが終了したことを`ExecutorService#awaitTermination(...)`で検知したら`JButton`を選択可に戻す
-- 仮設定のタスクが終了するとそのノードを展開
- すべてのノードのタスクが終了したことを`ExecutorService#awaitTermination(...)`で検知したら`JButton`を選択可に変更

* 参考リンク [#reference]
- [https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/tree/DefaultTreeCellRenderer.html DefaultTreeCellRenderer (Java Platform SE 8)]
[https://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/ExecutorService.html ExecutorService (Java Platform SE 8)]


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