Ruben Laguna's blog

Jan 18, 2010 - 2 minute read - Comments - cancel cancellable indicator java netbeans progress progresshandle requestprocessor runnable schedule task tasklistener ui

Cancellable tasks and progress indicators [Netbeans Platform]

Progress indicator (indeterminate mode) which allows to cancel the task The easiest way of having a cancellable progress indicator (Progress API) for a task in Netbeans Platform Application is the one below but it’s only worth for tasks that don’t update the progress indicator (indeterminate mode) until the task is finished. If you want to update the progress indicator (ProgressHandle) inside the task itself look at the second example.

ProgressHandle indeterminate

package com.rubenlaguna.en4j.mainmodule;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Logger;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.RequestProcessor;
import org.openide.util.TaskListener;

public final class MyCancellableActionNoProgressInformation implements ActionListener {

  //The RequestProcessor has to have allowInterrupt set to true!!
  private final static RequestProcessor RP = new RequestProcessor("interruptible tasks", 1, true);
  private final static Logger LOG = Logger.getLogger(MyCancellableActionNoProgressInformation.class.getName());

  public void actionPerformed(ActionEvent e) {

    Runnable runnable = new Runnable() {

    private final int NUM = 60000;

    public void run() {
      for (int i = 0; i < NUM; i**) {
        doSomething(i);
        if (Thread.interrupted()) {
          LOG.info("the task was CANCELLED");
          return;
        }
      }
    }

    private void doSomething(int i) {
      LOG.info("doSomething with " + i);
      return;
    }
  };

  final RequestProcessor.Task theTask = RP.create(runnable);

  final ProgressHandle ph = ProgressHandleFactory.createHandle("performing some task", theTask);
  theTask.addTaskListener(new TaskListener() {
    public void taskFinished(org.openide.util.Task task) {
      //make sure that we get rid of the ProgressHandle
      //when the task is finished
      ph.finish();
    }
  });

  //start the progresshandle the progress UI will show 500s after
  ph.start();

  //this actually start the task
  theTask.schedule(0);
  }
}

leads to

INFO [com.rubenlaguna.en4j.mainmodule.ImportEvernoteFile]: doSomething with 6619
INFO [com.rubenlaguna.en4j.mainmodule.ImportEvernoteFile]: doSomething with 6620
INFO [com.rubenlaguna.en4j.mainmodule.ImportEvernoteFile]: doSomething with 6621
INFO [com.rubenlaguna.en4j.mainmodule.ImportEvernoteFile]: doSomething with 6622
INFO [com.rubenlaguna.en4j.mainmodule.ImportEvernoteFile]: the task was CANCELLED

Progress indicator (determinate mode) which allows to cancel the task

This example show a ProgressHandle that it’s updated from the Runnable and it’s stil cancelable. In this case you are also somewhat to use the more cumbersome catch(InterruptedException) instead of just checking Thread.interrupted(). For some reason I couldn’t get the Thread.interrupted() to work in this case. Doing a Thread.sleep(0) will always throw a InterruptedException if the thread was interrupted (canceling a task will interrupt the thread if the RequestProcessor is created with the interruptThread=true).

Progress indicator (determinate mode)

package com.rubenlaguna.en4j.mainmodule;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Logger;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.Cancellable;
import org.openide.util.RequestProcessor;
import org.openide.util.Task;
import org.openide.util.TaskListener;

public final class MyCancellableAction implements ActionListener {

  private final static RequestProcessor RP = new RequestProcessor("interruptible tasks", 1, true);
  private final static Logger LOG = Logger.getLogger(MyCancellableAction.class.getName());
  private RequestProcessor.Task theTask = null;

  public void actionPerformed(ActionEvent e) {
    final ProgressHandle ph = ProgressHandleFactory.createHandle("task thats shows progress", new Cancellable() {
      public boolean cancel() {
        return handleCancel();
      }
    });

    Runnable runnable = new Runnable() {

      private final int NUM = 60000;

      public void run() {
        try {
          ph.start(); //we must start the PH before we swith to determinate
          ph.switchToDeterminate(NUM);
          for (int i = 0; i < NUM; i**) {
            doSomething(i);
            ph.progress(i);
            Thread.sleep(0); //throws InterruptedException is the task was cancelled
          }
        } catch (InterruptedException ex) {
          LOG.info("the task was CANCELLED");
          return;
        }
      }

      private void doSomething(int i) {
      LOG.info("doSomething with " + i);
      return;
      }
    };

    theTask = RP.create(runnable); //the task is not started yet

    theTask.addTaskListener(new TaskListener() {
      public void taskFinished(Task task) {
        ph.finish();
      }
    });

    theTask.schedule(0); //start the task

  }

  private boolean handleCancel() {
    LOG.info("handleCancel");
    if (null == theTask) {
      return false;
    }

    return theTask.cancel();
  }
}

leads to

INFO [com.rubenlaguna.en4j.mainmodule.MyCancellableAction]: doSomething with 5399
INFO [com.rubenlaguna.en4j.mainmodule.MyCancellableAction]: doSomething with 5400
INFO [com.rubenlaguna.en4j.mainmodule.MyCancellableAction]: doSomething with 5401
INFO [com.rubenlaguna.en4j.mainmodule.MyCancellableAction]: doSomething with 5402
INFO [com.rubenlaguna.en4j.mainmodule.MyCancellableAction]: doSomething with 5403
INFO [com.rubenlaguna.en4j.mainmodule.MyCancellableAction]: doSomething with 5404
INFO [com.rubenlaguna.en4j.mainmodule.MyCancellableAction]: doSomething with 5405
INFO [com.rubenlaguna.en4j.mainmodule.MyCancellableAction]: handleCancel
INFO [com.rubenlaguna.en4j.mainmodule.MyCancellableAction]: doSomething with 5406
INFO [com.rubenlaguna.en4j.mainmodule.MyCancellableAction]: the task was CANCELLED