JTableのセルに不確定進捗状態のJProgressBarを表示する
Total: 452
, Today: 1
, Yesterday: 0
Posted by aterai at
Last-modified:
概要
JTable
のセルに一定期間だけ不確定進捗状態のアニメーションを描画するJProgressBar
を適用します。
Screenshot
Advertisement
サンプルコード
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;
}
}
View in GitHub: Java, Kotlin解説
SwingWorker
でJProgressBar#setIndeterminate(true)
を設定して不確定進捗状態にしたJProgressBar
を生成してTableModel
の対象セルに設定SwingWorker
から進捗状況をInteger
で受け取る場合はセルレンダラーとして進捗状態を表示するJProgressBar
を一つだけ使いまわして使用する(JTableのセルにJProgressBarを表示参照)が、不確定進捗状態アニメーションを表示する場合はSwingWorker
からセルごとに異なるJProgressBar
自体を受け取ってセルレンダラーにする必要がある- 一つだけの
JProgressBar
を使用すると複数行で不確定進捗状態アニメーションを実行する場合やセルサイズが変更されて再描画する場合にアニメーション速度が速くなるなどの不具合が発生する
- 一つだけの
- 不確定進捗状態アニメーションは
JProgressBar
が親コンテナに配置されて表示可能状態になっていないと開始、描画されないので、このサンプルではBasicProgressBarUI#incrementAnimationIndex()
をオーバーライドしてpublic
にし、SwingWorder
で一定期間SwingWorder#publish(...)
と同時にこれを実行してアニメーションのコマを進めている
- JTableのセルにAnimated GIFを表示するのような
Animated GIF
で不確定進捗状態を表示するJLabel
をセルレンダラーとして使用する方法もある
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");
}
}