• category: swing folder: PauseResumeSwingWorker title: SwingWorkerの一時停止と再開 tags: [SwingWorker, JProgressBar, JTextArea] author: aterai pubdate: 2011-07-25T14:41:32+09:00 description: SwingWorkerで処理の一時停止と再開を行います。 image: https://lh6.googleusercontent.com/-3BCjKLnQbGM/Ti0AQV5nkwI/AAAAAAAAA_s/RY75ol3pFak/s800/PauseResumeSwingWorker.png hreflang:
       href: https://java-swing-tips.blogspot.com/2011/07/pause-and-resume-swingworker.html
       lang: en

概要

SwingWorkerで処理の一時停止と再開を行います。

サンプルコード

class RunAction extends AbstractAction {
  public RunAction() {
    super("run");
  }
  @Override public void actionPerformed(ActionEvent evt) {
    final JProgressBar bar1 = new JProgressBar(0, 100);
    final JProgressBar bar2 = new JProgressBar(0, 100);
    runButton.setEnabled(false);
    canButton.setEnabled(true);
    pauseButton.setEnabled(true);
    statusPanel.removeAll();
    statusPanel.add(bar1, BorderLayout.NORTH);
    statusPanel.add(bar2, BorderLayout.SOUTH);
    statusPanel.revalidate();
    worker = new SwingWorker<String, Progress>() {
      @Override public String doInBackground() {
        int current = 0;
        int lengthOfTask = 12; //filelist.size();
        publish(new Progress(Component.LOG, "Length Of Task: " + lengthOfTask));
        publish(new Progress(Component.LOG, "\n---------------------------\n"));
        while (current < lengthOfTask && !isCancelled()) {
          publish(new Progress(Component.LOG, "*"));
          if (!bar1.isDisplayable()) {
            return "Disposed";
          }
          try {
            convertFileToSomething();
          } catch (InterruptedException ie) {
            return "Interrupted";
          }
          publish(new Progress(Component.TOTAL, 100 * current / lengthOfTask));
          current++;
        }
        publish(new Progress(Component.LOG, "\n"));
        return "Done";
      }
      private final Random r = new Random();
      private void convertFileToSomething() throws InterruptedException {
        boolean flag = false;
        int current = 0;
        int lengthOfTask = 10 + r.nextInt(50);
        while (current <= lengthOfTask && !isCancelled()) {
          if (isPaused) {
            try {
              Thread.sleep(500);
            } catch (InterruptedException ie) {
              return;
            }
            publish(new Progress(Component.PAUSE, flag));
            flag ^= true;
            continue;
          }
          int iv = 100 * current / lengthOfTask;
          Thread.sleep(20); // dummy
          publish(new Progress(Component.FILE, iv + 1));
          current++;
        }
      }
      @Override protected void process(java.util.List<Progress> chunks) {
        for (Progress s: chunks) {
          switch (s.component) {
            case TOTAL: bar1.setValue((Integer) s.value); break;
            case FILE:  bar2.setValue((Integer) s.value); break;
            case LOG:   area.append((String) s.value); break;
            case PAUSE: {
              if ((Boolean) s.value) {
                area.append("*");
              } else {
                try {
                  Document doc = area.getDocument();
                  doc.remove(doc.getLength() - 1, 1);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
              }
              break;
            }
          }
        }
      }
      @Override public void done() {
        // ...
      }
    };
    worker.execute();
  }
}
private boolean isPaused = false;
class PauseAction extends AbstractAction {
  public PauseAction() {
    super("pause");
  }
  @Override public void actionPerformed(ActionEvent evt) {
    isPaused = (worker != null && !worker.isCancelled() && !isPaused);
    JButton b = (JButton) evt.getSource();
    b.setText(isPaused ? "resume" : "pause");
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、SwingWorker#doInBackground()内のループで一時停止のフラグを参照し、一時停止状態の場合は本来の処理(上記のサンプルではカウントアップするだけ)を行わずに、Thread.sleep(...)と停止中を表現するコンポーネントの更新(JTextAreaの文字列を点滅)のみ繰り返すSwingWorkerを使用しています。

参考リンク

コメント