概要

JTreeのノードにJProgressBarを表示するTreeCellRendererを設定します。

サンプルコード

class ProgressBarRenderer extends DefaultTreeCellRenderer {
  // 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.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 Container renderer = new JPanel(new BorderLayout()) {
    @Override public void updateUI() {
      super.updateUI();
      setOpaque(false);
    }
  };

  @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();
    if (o instanceof ProgressObject) {
      ProgressObject n = (ProgressObject) o;
      int i = n.getValue();
      progress.setValue(i);

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

      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;
  }
}
View in GitHub: Java, Kotlin

解説

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

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

参考リンク

コメント