パソコン活用研究5番街(Visual Basic、Excel(VBA)、BASIC プログラミング研究)
DoEvents
1 DoEvents
(1) DoEventsについて
VB(またはVBA)で時間のかかる処理をしてCPUを占有すると、Windowsは他のイベントを検出
できなくなります。そのような時DoEventsを使って、Windowsに制御を戻します。
簡単な実験をしてみましょう。図1のような簡単なものです。
図1
「count1 Start」、「count2 strat」のボタンを押すと、それぞれ1から9999までカウントしながら、表示する
という単純なものです。(ここには、カウントの表示が現れていませんが、カウントスタートすると、それぞれ
のボタンの上にカウントの表示が現れます)
VBのコードも非常に単純です。count1 start、count2 startボタンのコードだけ掲載しておきます。
見れば、わかると思いますが、それぞれのCheckBoxがONであれば、DoEventsを実行するように
なっています。
' count1 start ボタン Private Sub Command1_Click() cnt1 = 0 Do Until cnt1 >= 10000 CurrentX = 240: CurrentY = 240 Print Right$("000" + Str(cnt1), 4); cnt1 = cnt1 + 1 If Check1.Value = 1 Then DoEvents Loop End Sub ' count2 start ボタン Private Sub Command2_Click() cnt2 = 0 Do Until cnt2 >= 10000 CurrentX = 2040: CurrentY = 240 Print Right("000" + Str(cnt2), 4); cnt2 = cnt2 + 1 If Check2.Value = 1 Then DoEvents Loop End Sub |
(2) 『実験』
実験1 | <手順> DoEventsのCheckBoxを両方ともOFF 「count1 start」を押す カウントが始まったら、「count2 start」を押す |
<実行結果> count1のカウントがはじまりる count1のカウント中は、count2の方は何の反応も無し。 count1が9999までカウントし、終了すると、count2の カウントがスタート |
実験2 | <手順> DoEvents1のCheckBoxをON 「count1 start」を押す カウントが始まったら、「count2 start」を押す |
<実行結果> count1のカウントが始まる 「count2 start」を押した時点でcount1のカウントが停止し count2のカウントが始まる count2が9999までカウントし終了すると、停止していた count1のカウントが再開する |
実験1でわかるとおり、いったんVB(VBA)のプログラムが、時間のかかる処理に入ってしまうと、その
処理が終わるまで、次のイベントの処理(ここではcount2のカウント)は実行されず待たされることになります。
Windows(オペレーティングシステム =OS)は、「count2 start」ボタンのクリックを受け付けていますが、
この情報はキュー(処理待ちのイベントの列)に蓄積された状態で、待機中になります。
count1のカウントが終了すると、ようやくキューで待機していた次のイベント(count2のカウント)がOSから
VB(VBA)に渡されて(取り出されて)実行されます。
実験2では、DoEvents1のCheckBoxをONにしました。従って、「count2 start」ボタンが押されると、
DoEventsが実行された時点で、Windows(OS)にいったん制御が渡されて、次のイベント(count2のカウント)
の処理がVB(VBA)に渡されます(VBに取り出される)。その結果、VB(VBA)はcount1のカウントから抜け出し、
count2のカウントに実行を移します。count2のカウントが終了すると、count1のカウントに戻り、
DoEventsの次のコードから実行を再開します。
(3) 補足
他にもいろいろ、いろんなパターンで試してみてください。VB(VBA)プログラムとWindows(OS)間で
どう制御が移動しているか、理解できると思います。
例えば、DoEvents1のCheckBoxをONにして、「count1 start」を押し、カウントの途中でもう一度、
「count1 start」を押して見てください。
どうなったでしょうか。このように、DoEventsの記述のあるプロシージャでは、処理の
途中あるいは制御が他に移っている間に、もう一度同じプロシージャが呼び出されると、実行結果について
は予測できなくなります。(と、マニュアルにも書いてある)
上記の問題を防ぐには、プロシージャの先頭で
Command1.Enabled = False
と記述して、ボタンのクリック不可に、最後に
Command1.Enabuled = True
でクリック可に戻すようにするのがいいでしょう。
2 マルチスレッド
VBはVer6.0からマルチスレッドプログラムが可能になりました。
マルチスレッド化すると、上の問題に対してさらに違ったアプローチが可能になります。
ここでは、詳細はとりあげないことにします。