---
category: swing
folder: TableCellOfIndeterminateProgressBar
title: JTableのセルに不確定進捗状態のJProgressBarを表示する
tags: [JTable, JProgressBar, TableCellRenderer, SwingWorker, Animation]
author: aterai
pubdate: 2024-01-08T03:30:00+09:00
description: JTableのセルに一定期間だけ不確定進捗状態のアニメーションを描画するJProgressBarを適用します。
image: https://drive.google.com/uc?id=1j8bfUbhh4at4824_s2NPQ89sjHUw6N49
hreflang:
    href: https://java-swing-tips.blogspot.com/2024/01/paint-jprogressbar-with-indeterminate.html
    lang: en
---
* 概要 [#summary]
`JTable`のセルに一定期間だけ不確定進捗状態のアニメーションを描画する`JProgressBar`を適用します。

#download(https://drive.google.com/uc?id=1j8bfUbhh4at4824_s2NPQ89sjHUw6N49)

* サンプルコード [#sourcecode]
#code(link){{
private final JTable table = new JTable(model) {
  @Override public void updateUI() {
    super.updateUI();
    removeColumn(getColumnModel().getColumn(3));
    JProgressBar progress = new JProgressBar();
    TableCellRenderer renderer = new DefaultTableCellRenderer();
    TableColumn tc = getColumnModel().getColumn(2);
    tc.setCellRenderer((tbl, value, isSelected, hasFocus, row, column) -> {
      Component c;
      if (value instanceof JProgressBar) {
        c = (JProgressBar) value;
      } else if (value instanceof Integer) {
        progress.setValue((int) value);
        c = progress;
      } else {
        c = renderer.getTableCellRendererComponent(
            tbl, Objects.toString(value), isSelected, hasFocus, row, column);
      }
      return c;
    });
  }
};

class IndeterminateProgressBarUI extends BasicProgressBarUI {
  @Override public void incrementAnimationIndex() {
    super.incrementAnimationIndex();
  }
}

class BackgroundTask extends SwingWorker<Integer, Object> {
  private final Random rnd = new Random();

  @Override protected Integer doInBackground() throws InterruptedException {
    int lengthOfTask = calculateTaskSize();
    int current = 0;
    int total = 0;
    while (current <= lengthOfTask && !isCancelled()) {
      publish(100 * current / lengthOfTask);
      total += doSomething();
      current++;
    }
    return total;
  }

  private int calculateTaskSize() throws InterruptedException {
    int total = 0;
    JProgressBar indeterminate = new JProgressBar() {
      @Override public void updateUI() {
        super.updateUI();
        setUI(new IndeterminateProgressBarUI());
      }
    };
    indeterminate.setIndeterminate(true);
    // Indeterminate loop:
    for (int i = 0; i < 200; i++) {
      int iv = rnd.nextInt(50) + 1;
      Thread.sleep(iv);
      ProgressBarUI ui = indeterminate.getUI()
      ((IndeterminateProgressBarUI) ui).incrementAnimationIndex();
      publish(indeterminate);
      total += iv;
    }
    return 1 + total / 100;
  }

  private int doSomething() throws InterruptedException {
    int iv = rnd.nextInt(50) + 1;
    Thread.sleep(iv);
    return iv;
  }
}
}}

* 解説 [#explanation]
- `SwingWorker`で`JProgressBar#setIndeterminate(true)`を設定して不確定進捗状態にした`JProgressBar`を生成して`TableModel`の対象セルに設定
- `SwingWorker`から進捗状況を`Integer`で受け取る場合はセルレンダラーとして進捗状態を表示する`JProgressBar`を一つだけ使いまわして使用する([[JTableのセルにJProgressBarを表示>Swing/TableCellProgressBar]]参照)が、不確定進捗状態アニメーションを表示する場合は`SwingWorker`からセルごとに異なる`JProgressBar`自体を受け取ってセルレンダラーにする必要がある
-- 一つだけの`JProgressBar`を使用すると複数行で不確定進捗状態アニメーションを実行する場合やセルサイズが変更されて再描画する場合にアニメーション速度が速くなるなどの不具合が発生する
- 不確定進捗状態アニメーションは`JProgressBar`が親コンテナに配置されて表示可能状態になっていないと開始、描画されないので、このサンプルでは`BasicProgressBarUI#incrementAnimationIndex()`をオーバーライドして`public`にし、`SwingWorder`で一定期間`SwingWorder#publish(...)`と同時にこれを実行してアニメーションのコマを進めている

----
- [[JTableのセルにAnimated GIFを表示する>Swing/AnimatedIconInTableCell]]のような`Animated GIF`で不確定進捗状態を表示する`JLabel`をセルレンダラーとして使用する方法もある

#code{{
if (value instanceof JProgressBar) {
  label.setIcon(makeImageIcon(url, tbl, row, column));
  c = label;
} else if (...) 
// ...
public static Icon makeImageIcon(URL url, JTable table, int row, int col) {
  if (Objects.nonNull(url)) {
    ImageIcon icon = new ImageIcon(url);
    icon.setImageObserver((img, infoflags, x, y, w, h) -> {
      if (!table.isShowing()) {
        return false;
      }
      if ((infoflags & (FRAMEBITS | ALLBITS)) != 0) {
        int vr = table.convertRowIndexToView(row);
        int vc = table.convertColumnIndexToView(col);
        table.repaint(table.getCellRect(vr, vc, false));
      }
      return (infoflags & (ALLBITS | ABORT)) == 0;
    });
    return icon;
  } else {
    return UIManager.getIcon("html.missingImage");
  }
}
}}

* 参考リンク [#reference]
- [[JTableのセルにJProgressBarを表示>Swing/TableCellProgressBar]]
- [[JTableのセルにAnimated GIFを表示する>Swing/AnimatedIconInTableCell]]

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