• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:JTableのセルにJProgressBarを表示
#navi(../)
#tags(JTable, JProgressBar, TableCellRenderer, SwingWorker)
RIGHT:Posted by &author(aterai); at 2007-10-01
*JTableのセルにJProgressBarを表示 [#p482fe63]
* JTableのセルにJProgressBarを表示 [#p482fe63]
``JTable``のセルに``JProgressBar``を使用して進捗を表示します。

-&jnlp;
-&jar;
-&zip;
- &jnlp;
- &jar;
- &zip;

//#screenshot
#ref(http://lh3.ggpht.com/_9Z4BYR88imo/TQTUYeEtfWI/AAAAAAAAAl8/47mUyOKeiQY/s800/TableCellProgressBar.png)
#ref(https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTUYeEtfWI/AAAAAAAAAl8/47mUyOKeiQY/s800/TableCellProgressBar.png)

**サンプルコード [#tfa792a2]
** サンプルコード [#tfa792a2]
#code(link){{
class ProgressRenderer extends DefaultTableCellRenderer {
  private final JProgressBar b = new JProgressBar(0, 100);
  public ProgressRenderer() {
    super();
    setOpaque(true);
    b.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
  }
  @Override public Component getTableCellRendererComponent(JTable table, Object value,
                                               boolean isSelected, boolean hasFocus,
                                               int row, int column) {
    Integer i = (Integer)value;
    String text = "Done";
    if(i<0) {
      text = "Canceled";
    }else if(i<100) {
      b.setValue(i);
      return b;
    }
    super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column);
    return this;
  }
}
}}
#code{{
private final Executor executor = Executors.newCachedThreadPool();
//...
final int rowNumber = model.getRowCount();
SwingWorker<Integer, Integer> worker = new SwingWorker<Integer, Integer>() {
  private int sleepDummy = new Random().nextInt(100) + 1;
  private int lengthOfTask = 120;
  @Override protected Integer doInBackground() {
    int current = 0;
    while(current<lengthOfTask && !isCancelled()) {
      current++;
      try {
        Thread.sleep(sleepDummy);
      }catch(InterruptedException ie) {
        publish(-1);
        break;
      }
      publish(100 * current / lengthOfTask);
    }
    return sleepDummy*lengthOfTask;
  }
  @Override protected void process(java.util.List<Integer> chunks) {
    for(Integer value : chunks) {
      model.setValueAt(value, rowNumber, 2);
    }
    //model.fireTableCellUpdated(rowNumber, 2);
  }
  @Override protected void done() {
    String text = null;
    int i = -1;
    if(isCancelled()) {
      text = "Canceled";
    }else{
      try{
        i = get();
        text = "Done";
      }catch(Exception ignore) {
        ignore.printStackTrace();
        text = ignore.getMessage();
      }
    }
    System.out.println(rowNumber +":"+text+"("+i+"ms)");
  }
};
model.addTest(new Test("example", 0), worker);
executor.execute(worker); //1.6.0_18
//worker.execute(); //1.6.0_21
}}

**解説 [#nf3d3b9b]
** 解説 [#nf3d3b9b]
上記のサンプルでは、``add``ボタンをクリックすると、``JDK 6``の``SwingWorker``を使用したダミータスクが起動して、進捗状況が``Cell``内の``JProgressBar``で表示されます。

``ProgressRenderer``は、``JProgressBar``を一つ持ち、ダミータスクが動いている間は、その``JProgressBar``に値を設定して描画用のコンポーネントとして返し、タスクが終了(またはキャンセル)されたら``JLabel``(自分自身、``DefaultTableCellRenderer``)に文字列を設定して返すようになっています。

----
このサンプルでは、行番号をキーにしているため、例えばモデルから行を削除するときに実行中のタスクが手前の行などにあった場合はエラーが発生してしまいます。このため、実際には削除は行わず、フィルタを使って非表示にしています(参考: [[RowFilterでJTableの行をフィルタリング>Swing/RowFilter]])。

----
- メモ
-- [https://forums.oracle.com/forums/thread.jspa?threadID=1362600 Swing - Maximum number of SwingWorker objects in a Swing app?]
-- [https://forums.oracle.com/thread/1364600 Swing - Maximum number of SwingWorker objects in a Swing app?]

#code{{
public abstract class SwingWorker<T, V> implements RunnableFuture<T> {
  /**
   * number of worker threads.
   */
  private static final int MAX_WORKER_THREADS = 10;
}}

**参考リンク [#mad68939]
-[[SwingWorkerを使った処理の中断と進捗状況表示>Swing/SwingWorker]]
** 参考リンク [#mad68939]
- [[SwingWorkerを使った処理の中断と進捗状況表示>Swing/SwingWorker]]

**コメント [#m73864ef]
** コメント [#m73864ef]
- %%``Windows`` + ``Java 1.7.0-ea-b24``での動作がおかしいみたいです。 -- [[aterai]] &new{2007-12-19 (水) 21:08:43};%%
- メモ: [http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=87 Bug 87 - Icedtea 1.7.0 and SwingWorker problem] -- [[aterai]] &new{2008-01-31 (木) 15:56:51};
- ``JDK 1.6.0_18``での修正: [http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6799345 Bug ID: 6799345 JFC demos threw exception in the Java Console when applets are closed] -- [[aterai]] &new{2010-01-20 (水) 17:34:04};
-- 代わりに、``Executors.newCachedThreadPool().execute(worker);``のようにしているけど、これでいいのだろうか? 実行中にアプリケーションを終了する場合は、``ExecutorService#shutdown()``などを呼んだほうがよさそうだけど、このサンプルでは、``WindowConstants.EXIT_ON_CLOSE``で``VM``ごと落としているので、関係ない? -- [[aterai]] &new{2010-01-20 (水) 17:43:10};
-- 正常に動かなくなっている[http://java.sun.com/developer/technicalArticles/javase/swingworker/ Improve Application Performance With SwingWorker in Java SE 6]のサンプルがどう修正されるか、様子見。 -- [[aterai]] &new{2010-01-20 (水) 17:47:11};
- メモ: [http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514 Bug ID: 6826514 SwingWorker: done() called before doInBackground() returns, when cancelled] -- [[aterai]] &new{2010-02-04 (木) 16:54:27};
- メモ: [http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6880336 Bug ID: 6880336 SwingWorker deadlocks due one thread in the swingworker-pool] -- [[aterai]] &new{2010-03-15 (月) 18:01:12};
-- 修正されたようです。[http://java.sun.com/javase/6/webnotes/BugFixes6u21.html Java SE 6 Update 21 Bug Fixes] -- [[aterai]] &new{2010-07-08 (木) 21:48:24};

#comment