WisdomSoft - for your serial experiences.

6.6 進捗バー

JProgressBar クラスによる進捗バーを表示します。ダウンロードやファイルの入出力など、時間のかかる処理の進捗を表すことに応用できます。

6.6.1 進行状況の通知

プログラムが内部で時間のかかる処理を行うとき、ユーザーに無断で処理を進めるよりも、ユーザーに処理を行っていることをアピールし、処理が現在どの程度まで進行しているかを表示した方が、ソフトウェアを使う人間にとっては便利でしょう。特に、ソフトウェアが処理に集中している時間が長いと、何らかの方法でソフトウェアが処理を行っていることをアピールしなければ、ユーザーはソフトウェアがバグによって止まってしまったのか、処理を待っている状態なのかを判断することができません。

このように、時間のかかる処理の状態をユーザーに通知するには Swing の進捗バーが最も適していると考えられます。進捗バーは javax.swing.JProgressBar クラスで実装される、横、または縦に長い棒状のコンポーネントです。

javax.swing.JProgressBar クラス
java.lang.Object
  |
  +--java.awt.Component
        |
        +--java.awt.Container
              |
              +--javax.swing.JComponent
                    |
                    +--javax.swing.JProgressBar
public class JProgressBar extends JComponent implements SwingConstants, Accessible

このクラスは、最小値と最大値、そして現在の値を表すプロパティを持ちます。現在の値が最小値と等しい場合は棒は空の状態で、最大値に近づくほどバーが進みます。

表1 JProgressBar クラスのコンストラクタとメソッド(抜粋)
コンストラクタ 解説
public JProgressBar() 水平方向の進捗バーを作成する。
public JProgressBar(int orient) 指定された方向を持つ進捗バーを作成する。
public JProgressBar(int min, int max) 水平方向の進捗バーを、指定された最小値および最大値で作成する。
public JProgressBar(int orient, int min, int max) 指定された方向、最小値、および最大値で進捗バーを作成する。
public JProgressBar(BoundedRangeModel newModel) 水平方向の進捗バーを指定されたモデルで作成する。
メソッド
public void addChangeListener(ChangeListener l) 指定された ChangeListener を追加する。
public void removeChangeListener(ChangeListener l) 設定から ChangeListener を削除する。
public ChangeListener[] getChangeListeners() 設定されているすべての ChangeListener の配列を返す。
public void setValue(int n) 現在の値を設定する。
public int getValue() 現在の値を返す。
public void setMinimum(int n) 最小値を設定する。
public int getMinimum() 最小値を返す。
public void setMaximum(int n) 最大値を設定する。
public int getMaximum() 最大値を返す。
public void setOrientation(int newOrientation) 進捗バーの方向を設定する。
public int getOrientation() 進捗バーの方向返す。

進捗バーは、バーが進む方向を水平か垂直方向のいずれかに設定しなければなりません。JProgressBar クラスは SwingConstants インタフェースを実装しているため、垂直方向を表す JProgressBar.VERTICAL または水平方向を表す JProgressBar.HORIZONTAL を設定することができます。デフォルトで、バーは水平に設定されています。

進捗バーのプロパティの値が変更されると、オブジェクトに設定されている ChangeListener が呼び出されますが、進捗バーは入力を目的とするコンポーネントではないため、頻繁に利用されるものではないのでしょう。

コード1
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Test extends JFrame implements ActionListener {
	public static void main(String args[]) {
		JFrame win = new Test();
		win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		win.setBounds(10 , 10 , 400 , 300);
		win.show();
	}

	private JProgressBar bar = new JProgressBar(0 , 100);
	private JLabel label = new JLabel();
	private Timer timer;
	public Test() {
		getContentPane().add(bar , BorderLayout.NORTH);
		getContentPane().add(label , BorderLayout.SOUTH);

		timer = new Timer(100 , this);
		timer.start();
	}
	public void actionPerformed(ActionEvent e) {
		int value = bar.getValue();

		if (value >= bar.getMaximum()) timer.stop();
		bar.setValue(value + 1);
		label.setText("Value = " + value);
	}
}
実行結果
コード1 実行結果

コード1は、ウィンドウの上部に進捗バーを表示し、プログラムの開始から 100 ミリ秒単位でバーを進ませるプログラムです。バーの最小値は 0、最大値は 100 に設定されており、現在の値は 0 から開始され、増え続けます。

進捗バーの値の加算は、タイマーを使って行われています。タイマーは 100 ミリ秒ごとに Test クラスの actionPerformed() メソッドを呼び出すように設定されています。actionPerformed() メソッドは、呼び出されるたびに進捗バーの現在の値を調べ、それが最大値と同じかそれ以上でなければ、現在の値に 1 を加算してバーを進めます。このとき、現在の値をウィンドウ下部のラベルにテキストとして表示させています。

6.6.2 バーに文字を表示する

進捗バーの上には、ユーザーに対して処理内容などをテキストとして表示することができます。デフォルトではテキストの表示は OFF に設定されているため表示されませんが、setStringPainted() メソッドでテキストを表示するかどうかを設定することができます。現在、バーがテキストを表示しているかどうかは isStringPainted() メソッドを使います。

JProgressBar クラス setStringPainted() メソッド
public void setStringPainted(boolean b)
JProgressBar クラス isStringPainted() メソッド
public boolean isStringPainted()

setStringPainted() メソッドに true を指定すれば、進捗バーがコンポーネントの中央にテキストを表示するようになります。表示するテキストとなる文字列は、setString() メソッドで設定し getString() メソッドから取得することができます。

JProgressBar クラス setString() メソッド
public void setString(String s)
JProgressBar クラス getString() メソッド
public String getString()

デフォルトでは文字列が null に設定されていますが、これを setString() メソッドから目的の文字列を設定すると、バーに表示されます。

コード2
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Test extends JFrame implements ActionListener {
	public static void main(String args[]) {
		JFrame win = new Test();
		win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		win.setBounds(10 , 10 , 400 , 300);
		win.show();
	}

	private JProgressBar bar = new JProgressBar(0 , 100);
	private Timer timer;
	public Test() {
		bar.setStringPainted(true);

		getContentPane().setLayout(new FlowLayout());
		getContentPane().add(bar);

		timer = new Timer(100 , this);
		timer.start();
	}
	public void actionPerformed(ActionEvent e) {
		int value = bar.getValue();

		if (value >= bar.getMaximum()) timer.stop();
		bar.setValue(value + 1);
		bar.setString(value + "%");
	}
}
実行結果
コード2 実行結果

コード2では、進捗バーのテキスト表示を ON に設定しています。そして、タイマーによってリスナが呼び出されると、値を変更すると同時に進捗バーのテキストに現在の値を表示してます。このように、処理がどの程度進んでいるのかを、バーと共にテキストとして表示することができるのです。

6.6.2 バーに文字を表示する

進捗バーを含め、スライダーやスクロールバーなど、最小値と最大値、そして現在の値を保有するコンポーネントは共通のデータモデル javax.swing.BoundedRangeModel インタフェースを保有しています。このモデルは最小値、最大値、現在の値、内側の広さの 4 つの値を管理しています。ただし、内側の広さは PageUp や PageDown など、スクロールバーを大きく移動させるときに用いたり、つまみの大きさを決定する値として使われるものなので、進捗バーでは利用されません。

表2 BoundedRangeModel インターフェイスのメソッド
メソッド 解説
public void addChangeListener(ChangeListener x)

モデルに ChangeListener を追加する。

public void removeChangeListener(ChangeListener x) 設定されている指定した ChangeListener を削除する。
public void setValue(int newValue) 現在の値を設定する。
public int getValue() 現在の値を返す。
public void setExtent(int newExtent) 内側の幅を設定する。
public int getExtent() 内側の幅を返す。
public void setMaximum(int newMaximum) 最大値を設定する。
public int getMaximum() 最大値を返す。
public void setMinimum(int newMinimum) 最小値を設定する。
public int getMinimum() 最小値を返す。 
public void setRangeProperties(int value, int extent, int min, int max, boolean adjusting) このモデルのデータを一度に設定できるメソッド。
public boolean getValueIsAdjusting() 値の変更が、一連の変更の一部である場合に true を返す。
public void setValueIsAdjusting(boolean b) 値の変更を単一のイベントとして扱うかどうかを設定する。

BoundedRangeModel インタフェースで重要なのは、常に次のような関係が成立しなければならないということです。

最小値 <= 現在の値 <= 現在の値 + 内側の幅 <= 最大値

通常、この式に当てはまらないプロパティの設定には、例外を発生させるなどの対処が必要になるでしょう。

BoundedRangeModel インタフェースのデフォルトの実装は javax.swing.DefaultBoundedRangeModel クラスです。基本的に、このクラスは BoundedRangeModel インタフェースが要求する機能を忠実に実装しただけです。

javax.swing.DefaultBoundedRangeModel クラス
java.lang.Object
  |
  +--javax.swing.DefaultBoundedRangeModel
public class DefaultBoundedRangeModel extends Object implements BoundedRangeModel, Serializable

このクラスのコンストラクタは次のようなものがあります。

DefaultBoundedRangeModel クラスのコンストラクタ
public DefaultBoundedRangeModel()
public DefaultBoundedRangeModel(int value, int extent, int min, int max)

デフォルトでは、最大値が 100 でそれ以外の値は 0 に設定されます。パラメータを指定するコンストラクタの場合、第1パラメータから順に現在の値、内側の幅、最小値、最大値を一度に指定します。

BoundedRangeModel インタフェースは単純に数値プロパティを提供するだけなので、実際に値に対してフィルタを通す必要があるなど、よほど特殊な利用がない限り独自に実装する必要はないでしょう。通常は DefaultBoundedRangeModel クラスで十分と考えられます。