不確定進捗バー

このドキュメントでは、不確定進捗バーの実装に対して行った変更について説明します。このバーは、通常の進捗バーと似た外観の GUI コンポーネントであり、通常の進捗バーと同様に、時間のかかる操作が発生していることを示すアニメーションを使用します。ただし通常の進捗バーと異なり、不確定進捗バーは、操作完了までの程度は示しません。このドキュメントには次の節があります。

新規 JProgressBar API

特に指定しない場合は、いくつかの JProgressBar コンストラクタの中の 1 つを使用して作成される各進捗バーは、確定的です。setIndeterminate メソッドを使用すると、どのような JProgressBar 不確定進捗バーでも作成できます。

pb.setIndeterminate(true);

不確定進捗バーの表示は、常に動いています。進捗バーを確定的にして現在値を最小値に設定することで、アニメーションを停止し、進捗バーを解除することができます。次に例を示します。

pb.setValue(pb.getMinimum());
pb.setIndeterminate(false);

任意の時点で、確定モードと不確定モードを切り替えることができます。進捗バーが不確定かどうかは、isIndeterminate メソッドを使用して確認できます。

進捗バーが不確定な場合は、そのモデル (BoundedRangeModel) が無視されます。ただし、不確定進捗バー用に更新されなかった Look & Feel がこのモデルを使用する可能性があるため、モデルは存在して、適切なデータを含んでいる必要があります。

新規 UI デフォルト

進捗バーのアニメーションの速度を開発者が制御できるように、2 つの新規 UI デフォルトが追加されました。

ProgressBar.cycleTime UI デフォルトを使用して、Look & Feel の実装者やほかの開発者が、アニメーションの各サイクルにかかる時間を、ミリ秒単位で指定します。たとえば、サイクル時間が 500 の場合は、不確定モードの進捗バーのアニメーションは、秒あたり 2 回繰り返されます。デフォルトの描画コードは、この値を再ペイントの間隔、ボックスの長さ、およびコンポーネントの内部領域とともに使用し、ボックスが描画されるごとに跳躍する長さを決定します。この値は、再ペイント間隔の偶数倍にする必要があります。たとえば、再ペイントの間隔が 100 の場合は、有効なサイクル時間は 200、1000、1200 などであり、100 または 500 ではありません。ユーザが無効なサイクル時間を指定した場合は、不確定進捗バーのコードによって適切な値になるようにサイクル時間が自動的に増やされます。

再ペイントの間隔とサイクル時間のデフォルトは、次のように設定します。

UIManager.put("ProgressBar.repaintInterval", new Integer(250));
UIManager.put("ProgressBar.repaintInterval", new Integer(6000));

再ペイントの間隔とサイクル時間を入手するには、次のようにします。

int interval = UIManager.getInt("ProgressBar.repaintInterval");
int totalTime = UIManager.getInt("ProgressBar.cycleTime");

Sun から提供される BASIC、JLF、Motif、および Windows 実装では、進捗バーが不確定モードに切り替えられた場合にだけ、これらのデフォルトが確認されます。

新規 BasicProgressBarUI API

プログラマが進捗バーの Look & Feel を実装するときの役に立つように、次の API が BasicProgressBarUI クラスに追加されました。

ペイント関連のメソッド

アニメーションの現行フレームのインデックスを設定および取得するメソッド

カスタムのアニメーションスレッドを開始または停止するメソッド

従来は進捗バーのペイントをすべて事前に形成した paint メソッドは、現在では、進捗バーの不確定性関連のプロパティ値に応じて、すべての描画を paintDeterminate または paintIndeterminate に委譲します。進捗バーが不確定モードの場合は、paint メソッド (したがって paintIndeterminate メソッドも) は、「再ペイントの間隔」のミリ秒単位で実行されます。paintIndeterminate メソッドは進捗バーをアニメーションの状態に合わせてペイントする必要がありますが、この状態は getAnimationIndex メソッドで指定されます。

getBox メソッドを使用して、跳躍ボックスのペイントをカスタマイズできます。たとえば、MetalProgressBarUI がその paintIndeterminate メソッド内で getBox を呼び出してスーパークラスの BasicProgressBarUI にボックスを描画させ、その後輪郭線をボックスに追加します。getBox メソッドをオーバーライドすることで、paintIndeterminate を再び実装しなくても、跳躍ボックスのサイズと位置を完全に制御することができます。

paintIndeterminate または getBox をオーバーライドする場合は、有効な値で正しく循環するように、場合によっては incrementAnimationIndex もオーバーライドする必要があります。最初の描画を示す値は 0 です。規定により、2 番目の描画が 1、3 番目の描画が 2 というように続きます。最後の有効な値は、規定により、アニメーションサイクル内の総描画数から 1 を引いたものです。描画総数を判断するには、再ペイントの間隔と、おそらく、コンポーネントのサイズも考慮に入れる必要があります。「規定により」が暗黙に示すように、アニメーションのインデックスは、0 がアニメーションサイクルの始まりを示しているかぎり、希望する意味と値を持つように実装することができます。

提供されたアニメーションスレッドを使用しない場合は、2 つの xxxAnimationTimer メソッドをオーバーライドする必要があります。これで、定期的にアニメーションのインデックスを増加させ、進捗バー上で repaint を呼び出す独自の実装を提供できます。

進捗バーに関する開発作業の間接的な結果として、次の新しいメソッドが SwingUtilities に追加されました。

calculateInnerArea メソッドは、描画するすべてのクラスにとって有用です。このメソッドによって、コンポーネントが描画できる領域、つまり境界領域 (コンポーネントのインセット) を除くコンポーネントのすべての部分を含む四角形 (コンポーネントの座標系内) が返されます。

既存の進捗バー実装の変換

既存の Look & Feel の不確定進捗バーを変換することは、比較的単純です。既存の Look & Feel の進捗バー UI クラスが paint をオーバーライドしない、またはオーバーライドしても super.paint を呼び出す場合は、不確定進捗バーが自動的にサポートされます。WindowsProgressBarUIMotifProgressBarUI、および MetalProgressBarUI がこれに相当します。

Look & Feel の進捗バー UI クラスが BasicProgressBarUI のサブクラスであって、スーパークラスを呼び出さなくても paint をオーバーライドする場合は、確定モードが引き続き作用しますが、不確定モードも確定モードと同じように見えます。

既存の描画コードを paint メソッドから取り出し、新しい paintDeterminate メソッドに移す必要があります。不確定なペイントのためのコードは、新しい paintIndeterminate メソッドに移す必要があります。結局、上記の作業がすべて可能であれば、super.paint が呼び出されないかぎり、paint メソッドをオーバーライドすべきではありません。その理由は、paint メソッドの BasicProgressBarUI 実装がデフォルトのアニメーションスレッドを処理して、パフォーマンスと動作を拡張できるからです。

以後メンテナンスされない Sun のバージョンと Apple バージョンの両方の Mac の Look & Feel は、スーパークラスを呼び出さないで paint をオーバーライドする Look & Feel の例です。

不確定なペイントに対するスレッドのスキーマがすでにある場合は、startAnimationTimer および stopAnimationTimer をオーバーライドして、そのスキーマを使い続けることができます。または、単に独自のスレッドコードを削除して、提供されたスキーマを使うこともできます。

実装の詳細

BasicProgressBarUI クラスには、不確定進捗バーの実装のほとんどが含まれています。描画コードを除けば、実装コードのほとんどは、アニメーションスレッドを実装する Animator と、不確定モードの切り替えを待機する PropertyChangeHandler の、2 つの private 内部クラス内にあります。

Animator は、Swing の Timer クラスを使用してデフォルトのアニメーションスレッドを実装します。Animator インスタンスは、必要な場合に BasicProgressBarUI.startAnimationTimer メソッドによって作成されます。このメソッドは、進捗バーが不確定モードに切り替わったときにプロパティハンドラを呼び出します。進捗バーが不確定な場合に、Animator のタイマーが、「再ペイントの間隔」のミリ秒ごとに 1 回、アクションイベントを起動します。Animator のアクションイベントハンドラが、incrementAnimationIndex とその後に repaint を呼び出します (repaint は、paintIndeterminate を実行させる)。「再ペイントの間隔」は、ProgressBar.repaintInterval の UI デフォルトで指定され、これは startAnimationTimer にチェックされます。

PropertyChangeHandler は、自身を進捗バー上のプロパティのリスナーとして登録します。「不確定」なプロパティの変更が検出されると、ハンドラはその変更を通知して stopAnimationTimer または startAnimationTimer のどちらかを呼び出します。

新規 API のための Javadoc

javax.swing.JProgressBar

public void setIndeterminate(boolean newValue)

public boolean isIndeterminate()


javax.swing.plaf.basic.BasicProgressBarUI

protected void paintIndeterminate(Graphics g, JComponent c)

protected void paintDeterminate(Graphics g, JComponent c)

protected int getAnimationIndex()

protected void setAnimationIndex(int newValue)

protected void incrementAnimationIndex()

protected void startAnimationTimer()

protected void stopAnimationTimer()

protected Rectangle getBox(Rectangle r)


javax.swing.SwingUtilities

public static Rectangle calculateInnerArea(JComponent c, Rectangle r)