• 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

概要

概要

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

サンプルコード

サンプルコード

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;
    }
#spanadd

#spanend
    @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());
  public ProgressBarRenderer() {
    super();
    b.setOpaque(false);
    p.setOpaque(false);
    b.setStringPainted(true);
    b.setString("");
    b.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
  }
  private final Container renderer = new JPanel(new BorderLayout()) {
    @Override public void updateUI() {
      super.updateUI();
      setOpaque(false);
    }
  };
#spanadd

#spanend
  @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==null || !(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;
  }
#spanadd

#spanend
  @Override public Dimension getPreferredSize() {
    Dimension d = super.getPreferredSize();
    d.height = 18;
    return d;
  }
}
View in GitHub: Java, Kotlin

解説

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

解説

上記のサンプルでは、タスクが実行中の場合はノードの幅(アイコンと文字列の合計)と同じサイズのJProgressBarを配置するTreeCellRendererを作成し、これをJTree#setCellRenderer(...)で設定しています。
  • スタートボタンを押すと、JButtonを選択不可にし、SwingWorkerを起動して葉以外のノードをすべて捜査
  • 取得した各ノードで、ダミーのSwingWorkerExecutorService#execute(...)で起動し、進捗をJProgressBarを配置したTreeCellRendererで表示
    • ダミータスクが終了するとそのノードを展開
  • すべてのノードのタスクが終了したことをExecutorService#awaitTermination(...)で検知したら、JButtonを選択可に戻す
  • スタートボタンを押すとそのJButtonを選択不可に設定し、SwingWorkerを起動して葉以外のノードをすべて捜査
  • 取得した各ノードでSwingWorkerを起動し、進捗をJProgressBarを配置したTreeCellRendererで表示
    • 仮設定のタスクが終了するとそのノードを展開
  • すべてのノードのタスクが終了したことをExecutorService#awaitTermination(...)で検知したらJButtonを選択可に変更

コメント

参考リンク

コメント