はじめに
アプリケーションを書くときにタイマーが必要になることはよくあります。この記事では、タイマーの基本について説明し、さらにはタイマーの効果的な使い方についていくつかの例を取り上げます。
長年、フォーラムで初級者をサポートしてきて気付いた問題は、まず、多くの人がタイマーコントロールをストップウォッチタイマーあるいはカウントダウンタイマーとしてとらえていることです。しかし、それは違います。タイマーは、Xミリ秒ごとに単純にイベントを発生させるコントロールです。
では、それはどのような仕組みになっているのでしょう。この記事の最後で、いくつかのタイマー利用例を含んだVB6のダウンロード可能なプロジェクトを紹介します。これらの例を見れば、タイマーの仕組みについて理解が深まるでしょう。
ところで、タイマーは実際に何を行っているのでしょうか。タイマーはコントロールであり、実行時には何も表示されません。カウントや計算も行いません。プログラミングをする際に、表示、カウント、あるいは計算をしなければならないタイミングで、Xミリ秒ごとにイベントを発生させるだけのものです。
タイマーにはプロパティがごく少数しかなく、そのうちの2つ、つまりIntervalおよびEnabledだけがプログラミングに関係します。
Enabledは、単純にタイマーをオンやオフに切り替えます。
Intervalはイベントの発生間隔をミリ秒単位で表し、最大間隔は65535ミリ秒、つまり65秒です。また、注意しなければならないのは、タイマーコントロールは16ミリ秒ごとに動作するハードウェアタイマーにリンクしているので、毎回16ミリ秒目だけが正確であるということです。
最初の例では、タイマーを使用して時刻表示を継続的に更新する方法を見ていきます。
画面上の時刻の更新
目的
フォーム上のラベルに現在の日付と時刻を表示します。規則正しく更新され、誤差は最大1秒です。
方法
フォームにラベルを追加し、ラベル名をTime1とします。また、フォームにはタイマーも追加します。タイマーコントロールはどこに置いてもかまいません。私の場合は、視覚的に邪魔にならないように、下あるいは横の方に置くようにしています。
フォームのloadイベントでタイマーを起動して、アプリケーションが起動する瞬間から現在時刻を表示するようにします。タイマーを有効にして、タイマーの間隔は500ミリ秒に設定します。間隔を1000ミリ秒(1秒)に設定することもできますが、こうすると正確性の面で少々問題が起こります(もっとも、表示される時刻が1秒以上ずれることはありません)。状況によりときどきタイマーが正確に1秒後に動作しないことがあり、その場合は表示が1秒分スキップされてしまうのです。たいした問題ではありませんが、個人的には見づらいと感じます。
タイマーを正しく動作させるために必要となる主なコードをリスト1に示します。
リスト1
[Form_Load]
Timer1.Interval = 500
Timer1.Enabled = True
[Timer1_Timer]
Time1.Caption = "Date: " & Date & " - Time: " & Time
このアプリケーションを起動すると、フォーム上で時刻が継続的に更新されます。CPU使用量はごくわずかで、フォーム上の他の機能に影響を及ぼすこともありません。
動くオブジェクト
2番目の例では、タイマーを利用してアイテムや画像やアニメーションをキー操作で移動させる方法を見ていきます。
注意
Hキーは左への移動、Kキーは右、Uキーは上、Mキーは下への移動に使用します。
目的
キーボードを移動トリガとして使用し(W A S D X)、ピクチャボックスの中で画像を移動させます。
方法
この例では、ピクチャボックスの中でピクチャボックスを使用します。また、フォームのKeypreviewをTrueに設定して、キーの押下イベントをフォームで処理できるようにします。
フォーム全体を覆うように1つ目のピクチャボックスを置き、Scalemodeを「3-Pixel」に設定します。このピクチャボックスの中に、2つ目のやや小さいピクチャボックスを置きます。さらにタイマーをフォームに追加します。これも先ほどと同じようにフォームの端に置いてください。
次はコーディングですが、今回は少々おもしろい方法を採用し、トライステート型(Tristate)を作成します。これはブール型と似ていますが、Forward、Stop、Backwardという3つの値を取ります。それぞれの値は正の数(+1)、ゼロ(0)、負の数(-1)を表し、移動方向を決定するために使用します。
このトライステート型を使用して2つの変数を作成します。1つ目は画像を上下に移動させるP1UDで、もう1つは左右に移動させるP1LRです。
キーが押されたことを認識するにはフォームのKeyDownイベントを使用します。押されたキーに応じて、以下のリストのようにトライステート型の変数の値を設定します。
- Wキー: P1UD = Negative(上)
- Aキー: P1LR = Negative(左)
- Dキー: P1LR = Positive(右)
- Xキー: P1UD = Positive(下)
- Sキー: P1UDおよびP1LR = Zero
このように準備しておけば、上記のどのキーを押した場合でも、前進あるいは後退するように適切な変数が設定されます。中央にあるSキーを押すと、動きが止まるように両方の変数が設定されます。
この方式では、停止キー(S)を押すまで画像は動き続けます。お望みであれば、キーを離したときに動きが止まるようにすることもできます。そのためには、フォームのKeyUpイベントを使用して以下のリストのように変数をZeroに設定します。
- WキーまたはXキー: P1UD = Zero
- AキーまたはDキー: P1LR = Zero
その他のロジックについては、実際のサンプルコードを見てください。リスト2に、ピクチャボックスを動かすために必要なコードと宣言を示します。
リスト2
[General]
Private Enum Tristate
Neg = -1
Zero = 0
Pos = 1
End Enum
Private P1UD As Tristate
Private P1LR As Tristate
Private AutoStop As Boolean
[Form_Load]
Picture2.Picture = LoadPicture(App.Path & "/pic1.bmp")
Timer1.Interval = 50
Timer1.Enabled = True
SPM = 1 'steps per timed tick
[Form_KeyDown]
Select Case KeyCode
Case 65
P1LR = neg
Case 68
P1LR = pos
Case 87
P1UD = neg
Case 88
P1UD = pos
Case 83
P1LR = zero
P1UD = zero
End Select
[Form_KeyUp]
If AutoStop Then
Select Case KeyCode
Case 65, 68
P1LR = zero
Case 87, 88
P1UD = zero
End Select
End If
[Timer1_Timer]
Picture2.Top = Picture2.Top + SPM * P1UD
If Picture2.Top <= 0 Then P1UD = pos
If Picture2.Top >= Picture1.ScaleHeight Then P1UD = neg
Picture2.Left = Picture2.Left + SPM * P1LR
If Picture2.Left <= 0 Then P1LR = pos
If Picture2.Left >= Picture1.ScaleWidth Then P1LR = neg
お気付きになるかと思いますが、Timerイベントでは枠の位置を確かめて、画像が枠から出ないように動く方向を変えています。
変数SPMは、移動距離、つまりタイマーが時を刻むごとに画像が何ピクセル移動するかを設定するために使用します。
繰り返しになりますが、この方法でタイマーを使用すると、CPU使用量を減らし、アプリケーションの他のイベントに大きな影響を及ぼすことなくスムーズな動きを実現することができます。
アニメーション
最後の例では、タイマーを使ってアニメーションを作成します。
目的
選択ボックスをアニメーション表示し、枠線をフラッシュさせます。
方法
多くの描画ソフトウェアで選択ボックスがアニメーション表示されていることに気付いていましたか? どんな仕組みになっているか考えたことはありますか? 以下の簡単な例を見れば、このアニメーションを再現する方法がわかります。
これは単なるアニメーションとは少し違います。選択ボックスの位置、現在のアニメーションのステータス、およびその他いくつかの項目を記録しておく必要があります。
今回の例では、選択ボックスの描画と設定のコードについては説明せず、描画した後でそれをどのように動かすかという部分を取り上げます。
プロジェクト内で、フォームにピクチャボックスを追加し、フォーム全体を覆うように配置します。選択ボックスを作成するためのMouseUpおよびMouseDownイベントを追加します(実際のコードはダウンロード用のプロジェクトに含まれています)。フォームにタイマーを追加します。
選択ボックスの位置とサイズは、マウスクリック関連のイベントを通じて変数に格納しておきます。この変数は、選択ボックスアニメーションの上端、左端、幅、および高さの値を格納します。
選択ボックスの範囲が決まったら、タイマーを起動してアニメーションを実行します。マウスがクリックされたらタイマーを停止し、それによってアニメーションが停止するので、選択ボックスは元の状態に戻ります。
リスト3
[General]
Private Type RECT
Left As Long
Top As Long
Width As Long
Height As Long
End Type
Private SelRect As RECT
Private SelRect_S As Boolean
[Picture1_MouseDown]
If Button = vbLeftButton Then
Timer1.Enabled = False
If SelRect_S Then
Picture1.DrawStyle = vbSolid
Picture1.Line (SelRect.Left, SelRect.Top)- _
(SelRect.Left + SelRect.Width, SelRect.Top + _
SelRect.Height), , B
Picture1.DrawStyle = SelDrawType
End If
End If
[Picture1_MouseUp]
If Button = vbLeftButton Then
Timer1.Enabled = True
Timer1.Interval = 10
End If
[Timer1_Timer]
SelRect_S = Not (SelRect_S)
Picture1.DrawStyle = vbSolid
Picture1.DrawMode = 6 'inverted
Picture1.Line (SelRect.Left, SelRect.Top)-(SelRect.Left + _
SelRect.Width, SelRect.Top + SelRect.Height), , B
Picture1.DrawStyle = SelDrawType
このアニメーションでは、単純に選択ボックスを一定の間隔で反転表示させています。ダウンロード用のプロジェクトでは選択ボックスが破線になっているので、アニメーションにするとちょうどよい視覚的効果が得られます。
終わりに
一見したところ、タイマーコントロールは実用性がないように見えるかもしれません。初心者は最初にこれをストップウォッチタイマーであると誤解してしまうため、そのような使い方をしようとします。しかしこれがストップウォッチのような動作をせず、しかもその機能を実現するにはさまざまなコーディングが必要だと気付いた後は、多くの初級者がタイマーを役に立たないコントロールとしてそのまま脇に追いやり、CPUとアプリケーションを酷使する、長々しいループを多用した関数を使うことになります。
タイマーと、ここに挙げた例をきちんと理解すれば、アプリケーションとCPU使用量のどちらの点でも、タイマーの使用がどれほど効果的であるかがわかるでしょう。
この記事のダウンロード用プロジェクトには、それぞれ異なる時間間隔で使用される5つのタイマー機能が含まれています。
- 時刻の表示
- 画像の移動
- 選択ボックスのアニメーション
- シンプルな線画アニメーション
- カウントダウンタイマー
これらの例をタイマーの活用に役立てていただければと思っています。
Commodore 64の時代からコンピュータに親しみ、今では優れたプログラマー、デザイナーとして活躍。30代前半で、コンピュータから離れることはめったになく、コンピュータ関連の問題ならばいつでも助力とアドバイスを惜しまない人物。最近は本サイトに関するいくつかのプロジェクトに従事。