S-JIS[2013-02-22/2013-02-23] 変更履歴

Eclipseプラグイン 進捗状況表示

Eclipseプラグイン開発の進捗状況表示について。


概要

長く時間がかかる処理を実行する場合は、途中経過(進捗状況・プログレスバー)を表示するのがよい。


ProgressMonitorDialogとIRunnableWithProgressの例

進捗状況(プログレスバー)を出すダイアログとしてProgressMonitorDialogがある。
実行する処理本体はIRunnableWithProgressを実装する。

ExampleTask.java

import org.eclipse.core.runtime.IProgressMonitor;

import org.eclipse.jface.operation.IRunnableWithProgress;
public class EdampleTask implements IRunnableWithProgress {
	@Override
	public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
		monitor.beginTask("実験開始!", 100);
		try {
			for (int i = 0; i < 10; i++) {
				checkCancel(monitor);

				// 処理
				Thread.sleep(100);
				if (i == 5) {
					// throw new IllegalStateException("エラーを起こす実験");
				}

				monitor.worked(1);
			}
			for (int i = 0; i < 9; i++) {
				checkCancel(monitor);

				// 処理
				Thread.sleep(100);

				monitor.worked(10);
			}
		} finally {
			monitor.done();
		}
	}
	private void checkCancel(IProgressMonitor monitor) throws InterruptedException {
		if (monitor.isCanceled()) {
			throw new InterruptedException();
		}
	}
}

IRunnableWithProgressのrunメソッドに処理本体を記述する。

run()にはmonitorが渡されてくるので、最初にbeginTask()でタスク名と仕事量をセットする。 (仕事量が不明な場合はIProgressMonitor.UNKNOWNを指定する)
処理途中でmonitor.worked()を呼び出すことにより、進捗が進む。(worked()に渡した数値の合計最初に指定した仕事量と一致するようにするみたいだが、ずれていても動作はする)
最後にmonitor.done()を呼び出して終了する。

また、キャンセルボタンが押されたかどうかのチェックを随所で行わなければならない。
(ダイアログ上のキャンセルボタンが押されるとmonitor.isCanceled()がtrueになるので、そうなったらInterruptedExceptionをスローしなければならない)

呼び出す側:

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.swt.widgets.Shell;

import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
	ExampleTask task = new ExampleTask();

	Shell shell = 〜;
	ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
	try {
		dialog.run(true, true, task);
	} catch (InvocationTargetException e) {
		IStatus status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, "エラー発生", e.getCause());
		ErrorDialog.openError(shell, "error", "エラーが発生しました。", status);
	} catch (InterruptedException e) {
		MessageDialog.openInformation(shell, "canceled", "キャンセルされました。");
	}

呼び出す側は、IRunnableWithProgressのインスタンスを作ってProgressMonitorDialogのrunメソッドに渡すだけ。
ただしrunメソッドはキャンセルされることとその他の例外が発生する可能性があるので、そのハンドリングは行う必要がある。


SubProgressMonitorの例

タスクがいくつかのステップに分かれている場合、それぞれにmonitorを用意することが出来る。

Example2Task.java:

import org.eclipse.core.runtime.SubProgressMonitor;
public class Example2Task implements IRunnableWithProgress {
	@Override
	public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
		monitor.beginTask("実験開始!", 100);
		try {
			sub1(new SubProgressMonitor(monitor, 40));
			sub2(new SubProgressMonitor(monitor, 60));
		} finally {
			monitor.done();
		}
	}
	private void sub1(IProgressMonitor monitor) throws InterruptedException {
		monitor.beginTask("実験1", 10);
		monitor.subTask("実験1サブ");
		try {
			for (int i = 0; i < 10; i++) {
				checkCancel(monitor);
				Thread.sleep(100);
				monitor.worked(1);
			}
		} finally {
			monitor.done();
		}
	}
	private void sub2(IProgressMonitor monitor) throws InterruptedException {
		monitor.beginTask("実験2", 100);
		try {
			for (int i = 0; i < 100; i++) {
				checkCancel(monitor);
				monitor.subTask("実験2-" + i);
				Thread.sleep(100);
				monitor.worked(1);
			}
		} finally {
			monitor.done();
		}
	}

サブタスク用のProgressMonitorをSubProgressMonitorクラスで作る。
作る際に、親タスクの仕事量の内どれくらいの仕事になるかを割り当てる。
(上記の例ではトータルが100で、sub1に40、sub2に60(4割と6割)を割り当てている。sub1が完了すると親タスクが40終了することになる)

サブタスクは最初の例のタスクと同様にmonitorを使用する。
beginTask()によってサブタスクの仕事量を割り当てる。(親タスクで割り当てている数値とは無関係)
タスク名も第1引数で指定するが、これはどこにも表示されないようだ。
subTask()によって指定されたメッセージはプログレスバーの下に表示される。


Jobの例

バックグラウンドで処理を実行する例。
参考: きのさんのバックグラウンドで実行する

ProgressMonitorDialogを使う場合は処理本体をIRunnableWithProgressに書いたが、バックグラウンドで処理する場合はJobを実装する。

ExampleJob.java

import org.eclipse.core.runtime.jobs.Job;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
public class ExampleJob extends Job {
	public ExampleJob() {
		super("ジョブ実験");
	}
	@Override
	protected IStatus run(IProgressMonitor monitor) {
		monitor.beginTask("Job実験", 100);
		try {
			for (int i = 0; i < 50; i++) {
				checkCancel(monitor);
				monitor.subTask("実験サブ" + i);
				Thread.sleep(100);
				monitor.worked(2);
			}
			return Status.OK_STATUS;
		} catch (InterruptedException e) {
			return Status.CANCEL_STATUS;
		} finally {
			monitor.done();
		}
	}

処理本体の書き方は大体IRunnableWithProgressと同じだが、戻り値でIStatusを返すところが異なる。

呼び出す側:

	ExampleJob job = new ExampleJob();
//	job.setUser(true); //ダイアログを表示する
	job.schedule();

schedule()を呼び出すと実行される。
バックグラウンドで実行されるので、ほぼ同時に何回も呼び出した場合は、複数ジョブが並列に処理されることもある。


JobのサブクラスにWorkspaceJobというクラスもある。[2013-02-23]

参考: On the Job: The Eclipse Jobs API

WorkspaceJobの例


Eclipseプラグインへ戻る / Eclipseへ戻る / 技術メモへ戻る
メールの送信先:ひしだま