• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:SwingWorkerを使った処理の中断と進捗状況表示
#navi(../)
*SwingWorkerを使った処理の中断と進捗状況表示 [#ibc5942e]
>編集者:[[Terai Atsuhiro>terai]]~
作成日:2006-06-10~
更新日:&lastmod;
---
category: swing
folder: SwingWorker
title: SwingWorkerを使った処理の中断と進捗状況表示
tags: [SwingWorker, JProgressBar, JTextArea, Animation]
author: aterai
pubdate: 2006-06-10T11:46:45+09:00
description: JDK 6で新しくなったSwingWorkerを使って、処理の中断や進捗状況の表示更新などを行います。
image: https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTT8xXI-cI/AAAAAAAAAlQ/ueJc6P4EJVg/s800/SwingWorker.png
---
* 概要 [#summary]
`JDK 6`で新しくなった`SwingWorker`を使って、処理の中断や進捗状況の表示更新などを行います。

#contents
#download(https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTT8xXI-cI/AAAAAAAAAlQ/ueJc6P4EJVg/s800/SwingWorker.png)

**概要 [#zca06945]
JDK 6 で新しくなったSwingWorkerを使って、処理の中断や進捗状況の表示更新などを行います。
* サンプルコード [#sourcecode]
#code(link){{
class Task extends SwingWorker<String, String> {
  @Override public String doInBackground() {
    System.out.println("doInBackground() is EDT?: " + EventQueue.isDispatchThread());
    try {
      Thread.sleep(1000);
    } catch (InterruptedException ie) {
      return "Interrupted";
    }
    int current = 0;
    int lengthOfTask = 120; // list.size();
    publish("Length Of Task: " + lengthOfTask);
    publish("\n------------------------------\n");

#screenshot
    while (current < lengthOfTask && !isCancelled()) {
      try {
        Thread.sleep(50); // doSomething(file = list(current));
      } catch (InterruptedException ie) {
        return "Interrupted";
      }
      setProgress(100 * current / lengthOfTask);
      publish(".");
      current++;
    }
    publish("\n");
    return "Done";
  }
}

**サンプルコード [#p4592f3b]
#code{{
class RunAction extends AbstractAction{
class RunAction extends AbstractAction {
  public RunAction() {
    super("run");
  }
  public void actionPerformed(ActionEvent evt) {
    System.out.println("actionPerformed() is EDT?: "
        + EventQueue.isDispatchThread());

  @Override public void actionPerformed(ActionEvent evt) {
    System.out.println("actionPerformed() is EDT?: " + EventQueue.isDispatchThread());
    final JProgressBar bar = new JProgressBar();
    runButton.setEnabled(false);
    canButton.setEnabled(true);
    icon.animationStart();
    anil.startAnimation();
    statusPanel.removeAll();
    statusPanel.add(bar, BorderLayout.CENTER);
    statusPanel.add(bar);
    statusPanel.revalidate();
    bar.setIndeterminate(true);
    worker = new SwingWorker<String, String>() {
      @Override
      public String doInBackground() {
        System.out.println("doInBackground() is EDT?: "
            + EventQueue.isDispatchThread());
        try { // dummy task
          Thread.sleep(1000);
        }catch(InterruptedException ie) {
          return "Interrupted";

    worker = new Task() {
      @Override protected void process(List<String> chunks) {
        System.out.println("process() is EDT?: " + EventQueue.isDispatchThread());
        if (!isDisplayable()) {
          System.out.println("process: DISPOSE_ON_CLOSE");
          cancel(true);
          return;
        }
        int current = 0;
        int lengthOfTask = 120; //list.size();
        publish("Length Of Task: " + lengthOfTask);
        publish("------------------------------");
        while(current<lengthOfTask && !isCancelled()) {
          try { // dummy task
            Thread.sleep(50);
          }catch(InterruptedException ie) {
            return "Interrupted";
          }
          setProgress(100 * current / lengthOfTask);
          //worker.firePropertyChange("progress", current, current+1);
          current++;
        for (String message : chunks) {
          appendText(message);
        }
        return "Done";
      }
      @Override
      protected void process(java.util.List<String> chunks) {
        System.out.println("process() is EDT?: "
            + EventQueue.isDispatchThread());
        for(String message : chunks) {
          appendLine(message);

      @Override public void done() {
        System.out.println("done() is EDT?: " + EventQueue.isDispatchThread());
        if (!isDisplayable()) {
          System.out.println("done: DISPOSE_ON_CLOSE");
          cancel(true);
          return;
        }
      }
      @Override
      public void done() {
        System.out.println("done() is EDT?: "
           + EventQueue.isDispatchThread());
        icon.animationStop();
        anil.stopAnimation();
        runButton.setEnabled(true);
        canButton.setEnabled(false);
        statusPanel.remove(bar);
        statusPanel.revalidate();
        String text = null;
        if(isCancelled()) {
        if (isCancelled()) {
          text = "Cancelled";
        }else{
        } else {
          try {
            text = get();
          }catch(Exception ex) {
          } catch (InterruptedException | ExecutionException ex) {
            ex.printStackTrace();
            text = "Exception";
          }
        }
        appendLine(text);
        appendText(text);
      }
    };
    worker.addPropertyChangeListener(new ProgressListener(bar));
    worker.execute();
  }
}

class CancelAction extends AbstractAction{
class CancelAction extends AbstractAction {
  public CancelAction() {
    super("cancel");
  }
  @Override
  public void actionPerformed(ActionEvent evt) {
    if(worker!=null && !worker.isDone()) {

  @Override public void actionPerformed(ActionEvent evt) {
    if (worker != null && !worker.isDone()) {
      worker.cancel(true);
    }
    worker = null;
  }
}
}}
-&jnlp;
-&jar;
-&zip;

**解説 [#k7f99d1c]
以前のSwingWorker.javaから一部メソッド名が変更されていますが、基本的な使い方は一緒のようです。
- SwingWorker#execute()メソッドで処理が開始され、SwingWorker#doInBackground()メソッドが、バックグラウンドのスレッドで実行されます。
- EDTで実行する必要のある処理(上記の例では処理中にJTextAreaへのメッセージの書き出し)は、SwingWorker#process()メソッドをオーバーライドしてSwingWorker#publish()メソッドで呼び出したり、SwingWorker#firePropertyChange()を使えば良いようです。
- プログレスバーの処理には、SwingWorker#setProgress(int)が予め用意されているので、SwingWorker#addPropertyChangeListener(ProgressListener)を設定するだけで使用することが出来ます。
- 実行中の処理のキャンセルは、SwingWorker#cancel(boolean)メソッドで行います。キャンセルされたかどうかは、SwingWorker#isCancelled()メソッドで知ることが出来ます。
* 解説 [#explanation]
- `JDK 6`以前の`SwingWorker.java`から一部メソッド名が変更されているが、基本的な使用方法は同じ
- `SwingWorker#execute()`メソッドで処理が開始され、`SwingWorker#doInBackground()`メソッドがバックグラウンドのワーカースレッドで実行される
- `EDT`で実行する必要のある処理(上記の例では処理中に`JTextArea`へのメッセージの書き出し)は`SwingWorker#process()`メソッドをオーバーライドして`SwingWorker#publish()`メソッドで呼び出したり、`SwingWorker#firePropertyChange()`を使用する
- プログレスバーの処理には`SwingWorker#setProgress(int)`が予め用意されているので、`SwingWorker#addPropertyChangeListener(ProgressListener)`を設定するだけで使用可能
- `SwingWorker#setProgress(int)`で設定できるのは`0`から`100`で固定
#code{{
protected final void setProgress(int progress) {
  if (progress < 0 || progress > 100) {
    throw new IllegalArgumentException("the value should be from 0 to 100");
  }
  // ...
}}
- 実行中の処理のキャンセルは`SwingWorker#cancel(boolean)`メソッドで実行する
-- キャンセルされたかどうかは`SwingWorker#isCancelled()`メソッドで判定可能

EventQueue.isDispatchThread()を使うと以下のようになっています。
+ actionPerformed() is EDT?: true
+ doInBackground() is EDT?: false
+ process() is EDT?: true
+ done() is EDT?: true
----
- 現在のスレッドがイベントディスパッチスレッド(以下`EDT`)かどうかを調べる`EventQueue.isDispatchThread()`をこのサンプルで使用してテスト
+ `actionPerformed() is EDT?`: `true`
-- 現在のスレッド(このサンプルでは`EDT`)でボタンを選択不可にしたり、`SwingWorker#execute()`を実行している
+ `doInBackground() is EDT?`: `false`
-- ワーカースレッド(バックグラウンド)で重い処理を行い、`EDT`をブロックして停止状態にならないようにする
+ `process() is EDT?`: `true`
+ `done() is EDT?`: `true`
-- `Swing`関連のすべての作業(例えば`JProgressBar`の進捗表示更新)は`EDT`で行う必要があるので、`process()`か`done()`メソッド内で実行する

**参考リンク [#e809b8de]
-[[Improve Application Performance With SwingWorker in Java SE 6>http://java.sun.com/developer/technicalArticles/javase/swingworker/]]
-[[Worker Threads and SwingWorker>http://java.sun.com/docs/books/tutorial/uiswing/concurrency/worker.html]]
-[[JTableのセルにJProgressBarを表示>Swing/TableCellProgressBar]]
----
- `SwingWorker#process()`メソッド内などで`JPanel#isDisplayable()`を呼び、アプリケーション(`frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);`が設定されている)が終了している場合は、タスクを中断することで`SwingWorker`が生き残るのを防止

**コメント [#p903f9d0]
- 以前のSwingWorkerの使い方などは、[[Swing/AnimeIcon]]、[[Swing/RecursiveFileSearch]]などのソースコードやリンク先を参考にしてみてください。 -- [[terai]] &new{2007-02-22 (木) 17:57:58};
* 参考リンク [#reference]
- [https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/SwingWorker.html SwingWorker (Java Platform SE 8)]
//- [http://java.sun.com/developer/technicalArticles/javase/swingworker/ Improve Application Performance With SwingWorker in Java SE 6]
- [http://www.oracle.com/technetwork/articles/javase/swingworker-137249.html Improve Application Performance With SwingWorker in Java SE 6]
- [https://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html Worker Threads and SwingWorker]
- [[JTableのセルにJProgressBarを表示>Swing/TableCellProgressBar]]
- [[SwingWorkerで複数のJProgressBarを使用する>Swing/TwoProgressBars]]
- [[SwingWorkerの一時停止と再開>Swing/PauseResumeSwingWorker]]

* コメント [#comment]
#comment
- %%以前の`SwingWorker`の使い方などは、[[Timerでアニメーションするアイコンを作成>Swing/AnimeIcon]]、[[Fileの再帰的検索>Swing/RecursiveFileSearch]]などのソースコードやリンク先を参考にしてみてください。%% [[Fileの再帰的検索>Swing/RecursiveFileSearch]]は、`JDK 1.6`の`javax.swing.SwingWorker`を使用するように変更しました。 -- &user(aterai); &new{2007-02-22 (木) 17:57:58};
-- [[Timerでアニメーションするアイコンを作成>Swing/AnimeIcon]]は %%https://swingworker.dev.java.net/ にある%% `JDK 1.6`からバックポートされた`org.jdesktop.swingworker.SwingWorker`を使用するように変更しました。 -- &user(aterai); &new{2009-12-17 (木) 01:47:38};
-- `java.net`が新しくなって結構時間が経ったけど、http://java.net/projects/swingworker から`jar`がダウンロードできない…。[http://download.java.net/maven/2/org/jdesktop/swing-worker/1.1/ maven2 のリポジトリ]から取得するしかない?  -- &user(aterai); &new{2011-12-02 (金) 17:23:45};
-- 上記の`jar`は、`1.1`なので、`1.2`が必要なら、 ソースを取得して、`ant bundles` -- &user(aterai); &new{2011-12-02 (金) 17:38:31};

#comment