概要

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

サンプルコード

class RunAction extends AbstractAction {
  public RunAction() {
    super("run");
  }

  @Override public void actionPerformed(ActionEvent evt) {
    JProgressBar bar1 = new JProgressBar(0, 100);
    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>() {
      private final Random r = new Random();
      @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 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);
          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を使用しています。

参考リンク

コメント