5.9 タイマー
5.9.1 定期的なイベントの発生
定期的に特定のメソッドを呼び出すことができれば、アニメーションを行うオブジェクトのイベントを発生させる引き金となることができるでしょう。このようなタイマーの機能は AWT には存在しなかったため、アニメーションの実装はスレッドを用いました。しかし、Swing ではタイマーが追加されたため、タイマーを用いてアニメーションを行ったり、何かを監視するといったプログラムを作ることができます。
タイマーは javax.swing.Timer クラスで実装されています。
java.lang.Object | +--javax.swing.Timer
public class Timer extends Object implements Serializable
Timer クラスはコンストラクタにメソッドを呼び出す時間間隔をミリ秒で指定します。タイマーを起動すると、設定されているミリ描画経過する度に指定したリスナのメソッドを呼び出すという仕組みになっています。
コンストラクタ | 解説 |
---|---|
public Timer(int delay, ActionListener listener) | ミリ秒単位の delay ごとにリスナへ通知するタイマーを生成します。 |
メソッド | |
public void addActionListener(ActionListener listener) | アクションリスナーを追加します。 |
public void removeActionListener(ActionListener listener) | 指定されたアクションリスナを削除します。 |
public ActionListener[] getActionListeners() | タイマーに登録されたすべてのアクションリスナーの配列を返します。 |
public void setDelay(int delay) | 連続するアクションイベント間の遅延時間をミリ秒単位で設定します。 |
public int getDelay() | アクションイベントのトリガ間の遅延時間 (ミリ秒単位) を返します。 |
public void setInitialDelay(int initialDelay) | 初期遅延を設定します。 |
public int getInitialDelay() | 初期遅延を返します。 |
public void start() | タイマーを起動し、リスナへのアクションイベントの送信を開始します。 |
public boolean isRunning() | タイマーが実行中であれば、true を返します。 |
public void stop() | タイマーを停止し、リスナへのアクションイベントの送信を停止します。 |
public void restart() | タイマーを再起動します。保留中のトリガがあれば取り消し、初期遅延を使用してトリガします。 |
Timer クラスの主なメソッドは表1に記します。コンストラクタや、addActionListener() メソッドで指定している java.awt.event.ActionListener インタフェースは、何らかのアクションが発生したときに受け取るメソッド actionPerformed() メソッドを定義しているリスナを表します。
public void actionPerformed(ActionEvent e)
このメソッドは、オブジェクトの役割として与えられている動作が発生したときに呼び出されるもので、その内容(イベントの実体)は抽象化されています。例えば、Timer クラスのアクションとは時間が経過した状態を表すと考えられますし、ボタンコンポーネントであればボタンが押されたということがアクションの発生につながると考えることができます。
actionPerformed() メソッドに渡されるのは java.awt.event.ActionEvent クラスのオブジェクトです。
java.lang.Object | +--java.util.EventObject | +--java.awt.AWTEvent | +--java.awt.event.ActionEvent
public class ActionEvent extends AWTEvent
このクラスはアクションイベントの情報を提供するためのもので、アクションに関連したコマンド文字列を返す getActionCommand() メソッドや、グリニッジ標準時 1970 年 1 月 1 日 00:00:00 からイベント発生時刻までの時間をミリ秒単位で返す getWhen() メソッドなどが定義されています。
public String getActionCommand()
public long getWhen()
getActionCommand() を使えばイベントの発生元から、イベントの処理先に状態に応じたコマンドを通知することができるようになります。getWhen() メソッドが返す値は java.util パッケージ内の Date クラスや Calendar クラスを用いて時間に変換することができます。
Timer オブジェクトを生成してタイマーを起動させると、定期的に actionPerformed() メソッドが呼び出されるようになります。この処理はタイマーを停止するまで続けられるため、永続的なアニメーション処理や定期的なシステムの監視などに利用できるでしょう。
import javax.swing.*; import java.awt.*; import java.awt.event.*; public class Test extends JComponent { public static void main(String args[]) { JFrame win = new JFrame(); win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); win.setBounds(10 , 10 , 400 , 300); win.getContentPane().add(new Test()); win.show(); } private String param = ""; public Test() { Timer timer = new Timer(100 , new ActionListener() { public void actionPerformed(ActionEvent e) { param = new java.util.Date(e.getWhen()).toString(); repaint(); } }); timer.start(); } public void paintComponent(Graphics g) { g.drawString(param , 0 , g.getFontMetrics().getHeight()); } }
コード1の Test() コンストラクタでは Timer インスタンスを 100 ミリ秒に設定して作成しています。このタイマーを起動すると、100 ミリ秒経過するたびに保有するアクションリスナが呼び出されます。プログラムは内部クラスの ActionListener インタフェースの実装を 100 ミリ秒単位で呼びだし、イベントが発生したときの時間を記録します。paintComponent() メソッドでは記録された時間を表示しているため、結果としてアプリケーションは現在時刻を描画する時計アプリケーションと化しているでしょう。100 ミリ秒単位でアクションが発生時刻を描画し続ければほとんどリアルタイムです。
ただし、タイマーを使って時間の経過を計測しようと考えてはなりません。イベントが発生するのは指定した時間間隔が経過してからという意味で、100 ミリ秒を指定したからといって、確実に100ミリ秒ごとに呼び出されるわけではありません。メソッドを処理している時間や、他のイベントを処理している時間がこれに加わります。