TITLE:SwingWorkerを使った処理の中断と進捗状況表示

SwingWorkerを使った処理の中断と進捗状況表示

編集者:Terai Atsuhiro
作成日:2006-06-10
更新日:2021-08-07 (土) 14:34:10

概要

JDK 6 で新しくなったSwingWorkerを使って、処理の中断や進捗状況の表示更新などを行います。

#screenshot

サンプルコード

 class RunAction extends AbstractAction{
   public RunAction() {
     super("run");
   }
   public void actionPerformed(ActionEvent evt) {
     System.out.println("actionPerformed() is EDT?: "
         + EventQueue.isDispatchThread());
     runButton.setEnabled(false);
     canButton.setEnabled(true);
     icon.animationStart();
     statusPanel.removeAll();
     statusPanel.add(bar, BorderLayout.CENTER);
     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";
         }
         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++;
         }
         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());
         icon.animationStop();
         runButton.setEnabled(true);
         canButton.setEnabled(false);
         statusPanel.remove(bar);
         statusPanel.revalidate();
         String text = null;
         if(isCancelled()) {
           text = "Cancelled";
         }else{
           try {
             text = get();
           }catch(Exception ex) {
             ex.printStackTrace();
             text = "Exception";
           }
         }
         appendLine(text);
       }
     };
     worker.addPropertyChangeListener(new ProgressListener(bar));
     worker.execute();
   }
 }

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

解説

以前の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()メソッドで知ることが出来ます。

EventQueue.isDispatchThread()を使うと以下のようになっています。

  1. actionPerformed() is EDT?: true
  2. doInBackground() is EDT?: false
  3. process() is EDT?: true
  4. done() is EDT?: true

参考リンク

コメント