Regress or Progress > VB For Beginners > Introduction to Basic Programming > タイマープログラム

2. タイマープログラム

あると便利なタイマープログラムです。ここではタイマープログラムの作り方を説明していきます。

2004.03.05 やっと完成しました


■タイマープログラムの概要

ここで作成するタイマーの概要は以下の通りです。

・99時間99分99秒(100時間40分39秒)まで計測することができる。
・計測中に一時停止、再開ができる。
・設定時間入力時に数字しか入力できないようにする。
・設定時間入力時にテキストボックスにフォーカスが移った時に全て選択する。

■画面イメージ


テキストボックスは左からText1, Text2, Text3
コマンドボタンは上からCommand1, Command2
これに加えて、タイマーコントロールを追加し、名前をTimer1とします。
※好みの名前に変えても構いませんが、このページでは上記の名前でコードを説明していきますので、適宜読み替えてください。

■デザインイメージ


Label2はCaptionプロパティを空白(””)に設定しておいてください。
ここでは、デザインの都合で表示しています。

■変数・関数の定義 ※コードは必ずしも紹介する順番で書く必要はありません。ダウンロード用のソースも下記とは異なります。

・タイマーの残り時間を記憶するために、フォームモジュール全体で使う変数を定義します。

Private RestTime As Long ' 残り時間

・同様にしてタイマーの動作を途中で停止/再開できるようにするために次の変数を定義します。
−タイマーが実行中であるかを記憶する変数
−タイマーのカウントが動作しているかを記憶する変数

Private Activated As Boolean ' タイマーを実行中か
Private Working As Boolean ' タイマーが動作中か

・テキストボックスに数値しか入力できないようにするために、次の関数を用意し、テキストボックスに入力された文字を判別します。

Private Function CharacterCheck(KeyAscii As Integer) As Integer
Dim str As String

str = Chr(KeyAscii)
If str >= "0" And str <= "9" Then
CharacterCheck = KeyAscii
ElseIf KeyAscii = vbKeyBack Then
CharacterCheck = KeyAscii
Else
CharacterCheck = 0
End If

End Function

・テキストボックスのKeyPressイベントが発生したときに、上記で定義した関数を利用して入力された文字のチェックを行います。

Private Sub Text1_KeyPress(KeyAscii As Integer)
' 数字のみの入力を有効とします(以下同様)
KeyAscii = CharacterCheck(KeyAscii)
End Sub

Private Sub Text2_KeyPress(KeyAscii As Integer)
KeyAscii = CharacterCheck(KeyAscii)
End Sub

Private Sub Text3_KeyPress(KeyAscii As Integer)
KeyAscii = CharacterCheck(KeyAscii)
End Sub

・テキストボックスからフォーカスが離れたときに(LostFocusイベント)、テキストボックスが空白でないかをチェックする関数を定義します。逆に、フォーカスを得たときには、入力しやすくするために入力され要るすべての文字を自動的に選択するようにします。

Private Function NullCheck(txt As String) As String
If txt = "" Then
NullCheck = "0"
Else
NullCheck = txt
End If
End Function

Private Sub Text1_GotFocus()
' フォーカスを得た時に全てを選択します(以下同様)
Text1.SelStart = 0
Text1.SelLength = 2
End Sub

Private Sub Text1_LostFocus()
' テキストボックスが空白であるかチェックします(以下同様)
Text1.Text = NullCheck(Text1.Text)
End Sub

Private Sub Text2_GotFocus()
Text2.SelStart = 0
Text2.SelLength = 2
End Sub

Private Sub Text2_LostFocus()
Text2.Text = NullCheck(Text2.Text)
End Sub

Private Sub Text3_GotFocus()
Text3.SelStart = 0
Text3.SelLength = 2
End Sub

Private Sub Text3_LostFocus()
Text3.Text = NullCheck(Text3.Text)
End Sub

・タイマーを開始する関数を定義します。この関数はボタン(Command1)が押されたときに必要に応じて呼び出します。CLng関数はLong型に変換する関数です。さらに厳密に言うと、Val(Text1)と数値化したほうがいいのですが、ここでは特に問題はないと思われます。この辺がVisual Basicの便利なところですね。まとも(?)にしたい方はCLng(Val(Text1))のようにして下さい。さらに(2回目)、テキストボックスの値を取得するときにText1だけ書いていいのかと思われた方もいらっしゃるのではないでしょうか?そうです。本当はText1.Textのはずですね。ただ、Textboxを名前だけで指定するとTextプロパティがデフォルトとなるので、Text1としてもText1.Textと同値になるのです。このことはLabelコントロールのCaptionプロパティにも当てはまります。※.NET以降は省略不可になりました。

Private Sub StartTimer()
RestTime = CLng(Text1) * 3600 + CLng(Text2) * 60 + CLng(Text3)

If RestTime <= 1 Then
MsgBox "時間を1秒以上に設定してください"
Exit Sub
End If


ShowRestTime

With Text1
.Enabled = False
.BackColor = &HC0C0C0
End With

With Text2
.Enabled = False
.BackColor = &HC0C0C0
End With

With Text3
.Enabled = False
.BackColor = &HC0C0C0
End With

Activated = True
Working = True
Timer1.Enabled = True

Command1.Caption = "ストップ"
End Sub

・タイマーを停止/再開する関数を定義します。この関数はボタン(Command1)が押されたときに必要に応じて呼び出します。
 変数Workingはタイマーの実行中に、タイマーのカウントは動作しているかを記憶しておくための変数です。これは、停止/再開の機能を実現するために必要です。

Private Sub StopTimer()
Working = False
Timer1.Enabled = False
End Sub

Private Sub ReStartTimer()
Working = True
Timer1.Enabled = True
End Sub

・タイマーをリセットする関数を定義します。この関数は「リセット」ボタンが押されたときに呼び出します。変数などを全て初期化します。

Private Sub ResetTimer()
' タイマーを停止させます
Timer1.Enabled = False

' 変数を初期化
RestTime = 0
Activated = False
Working = False

With Text1
.Enabled = True
.BackColor = vbWhite
End With

With Text2
.Enabled = True
.BackColor = vbWhite
End With

With Text3
.Enabled = True
.BackColor = vbWhite
End With

Command1.Caption = "スタート"
Text1.Text = "0"
Text2.Text = "0"
Text3.Text = "0"

End Sub

・タイマー機能の実装をします。まず、タイマーコントロールのIntervalが0になっているので、値を変更します。普通は1000(ミリ秒)としますが、タイマーコントロールは厳密には動作せず、若干の遅れが生じるので、990〜995あたりに設定すると、誤差を減らすことができます。今回は1000で問題ありません。

・タイマーのカウントを実際に行う関数を定義します。この関数では、残り時間を画面に表示します。画面が最小化になっている場合は、タスクバーの部分に残り時間を表示するようにします。
時間の計算について少し説明をしておきます。当たり前の話ですが、60秒=1分で、60分=1時間=3600秒です。このソフトでは、一番最初に定義した変数RestTimeに残り時間を秒で記憶しておき、1秒ごとに1ずつ減らしていきます。残り時間の表示形式は、〇〇時間〇〇分〇〇秒という形式にします。ただし、1時間未満の時には〇〇時間の部分を表示せず、1分未満の時には〇〇分も表示しないようにします。まず、RestTimeを3600で割った商を変数h(時間に該当します)に代入します。ここで注意することは、時間は全て整数で扱うということです。Integer型やLong型は整数型なので今回は特に気にする必要はありません。次のにRestTimeから今求めたh×3600を引いた値を60で割った商を求め、変数m(分に該当します)に代入します。さらに、RestTimeからh×3600とm×60を引いた値を変数sに代入すれば、それが秒の値となります。時間、分、秒の3つが求められたら、次は〇〇時間〇〇分〇〇秒形式でラベルに表示します。下のコードでは、RestTimeが3600以上のときは〇〇時間〇〇分〇〇秒の形式、60以上のときは〇〇分〇〇秒の形式、そうでないとき、すなわち1分未満のときは〇〇秒のみの形式でそれぞれ表示行います。それぞれの値が10未満のときも2ケタで表示するようにFormat関数を利用しています。引数に"00"を指定することによって、強制的に2ケタ表示になります。ただし、先頭の単位についてはそのまま表示します。この辺は各自の好みによって変わるものなので、好きなように変更してみてください。ここまでできたら、ラベルに(ここではLabel2)に表示します。最後に、ウィンドウが最小化状態になっていても残り時間が分かるように、最小化状態かどうかを調べ、最小化状態であればタスクバーの部分に残り時間を表示します。最小化されていないときは、通常表示とします。ウィンドウの状態にかかわらず常に表示したい場合は、If文をはずして、Me.Caption = Retのみにします。

Private Sub ShowRestTime()
Dim h As Long, m As Long, s As Long
Dim Ret As String

h = RestTime \ 3600 ' 時間
m = (RestTime - h * 3600) \ 60 ' 分
s = RestTime - (h * 3600) - (m * 60) ' 秒

If RestTime >= 3600 Then
Ret = Format(h, "#0") & " 時間 " & Format(m, "00") & " 分 " & Format(s, "00") & " 秒"
ElseIf RestTime >= 60 Then
Ret = Format(m, "#0") & " 分 " & Format(s, "00") & " 秒"
Else
Ret = Format(s, "#0") & " 秒"
End If

' 残り時間を表示します
Label2.Caption = Ret

' 最小化の場合、タスクバーに残り時間を表示します
If Me.WindowState = vbMinimized Then
Me.Caption = Ret
Else
Me.Caption = "タイマー"
End If

End Sub

・上で定義したShowRestTime関数(正確にはプロシージャですが)は毎秒実行する必要があります、Timer1のTimerイベントの部分に実行するコードを書きます。このコードはIntervalで設定した間隔ごとにTimerイベントが発生し、実行されます。ここではRestTimeの値を1減らして、ShowRestTimeを実行します。この際、残り時間が0になったときは、時間になった旨を伝えるメッセージを表示します。この部分は、他のメッセージを表示したり、音を鳴らしたり、他のプログラムを起動したり・・・などいろいろなことに応用できますので、ぜひ試してみてください。あと、終了したあとはResetTimerを実行して、タイマーを初期化するのを忘れないでください。(必ずしも初期化しなければいけないということはありませんが)

Private Sub Timer1_Timer()

' 1秒ごとにカウントを減らします
RestTime = RestTime - 1

' 残り時間を表示します
ShowRestTime

' 時間になったらメッセージを表示しタイマーを初期化します
If RestTime <= 0 Then
MsgBox "時間です"
ResetTimer
End If

End Sub

・もうちょっとで完成です。まだ、ボタンを押したときのコードを書いていませんでしたね。Command1はタイマーの状態によって動作が異なります。というか必然的にそうなってしまうのです。ボタンを分けてもいいのですが、実際のストップウォッチやタイマーは同様の機能をひとつのボタンでやっていますよね?今回は実用性を出したかったので、このようにしました。さて、Command1の動作は3通りに分かれます。まず、タイマーを開始する機能、次に、停止する機能(再開可)、そして、再スタートする機能です。この判断を行うために、最初にActivated とWorkingの2変数を定義したのです。変数Activatedはタイマーが実行中であるかを、変数Workingはタイマーのカウントが実際に動いているかを記憶しておく変数だということは上のほうで述べたとおりです。

Private Sub Command1_Click()
If Activated = True And Working = True Then
' タイマーを停止します(再スタート可能)
StopTimer
Command1.Caption = "スタート"
ElseIf Activated = True And Working = False Then
' タイマーを再スタートします
ReStartTimer
Command1.Caption = "ストップ"
Else
' タイマーを開始します
StartTimer
End If
End Sub


Private Sub Command2_Click()
' タイマーをリセット(初期化)します
ResetTimer
Label2.Caption = "リセットされました"
End Sub

・最後にプログラムが起動したときに、変数の初期化をしておきましょう。ここは、ResetTimerの1行だけを実行してもOKです。ここでは必要最低限の初期化しか実行していませんが、せっかく作った関数だからそっちのほうがいいかも。

Private Sub Form_Load()
' 初期化
RestTime = 0
Activated = False
Working = False
End Sub

・以上でタイマーは完成です。おつかれさまでした。。。今回は実用性を考慮して紹介したのでちょっと難しかったかもしれませんが、使えそうなプログラムができたかと思います。
改善の余地はまだまだあると思うので、自分なりにバージョンアップしてみてください。

ソースのダウンロード(8.60KB)


▲このページのトップに戻る


Copyright (C) 2004 Masahiro Sato. All Rights Reserved.
mahiro@everlasting-progress.com