TITLE:SwingWorkerの一時停止と再開

Posted by at 2011-07-25

SwingWorkerの一時停止と再開

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

  • &jnlp;
  • &jar;
  • &zip;
PauseResumeSwingWorker.png

サンプルコード

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 = !flag;
            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{
                  javax.swing.text.Document doc = area.getDocument();
                  doc.remove(area.getDocument().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の文字列を点滅)のみ繰り返すようになっています。

参考リンク

コメント