パソコン活用研究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からマルチスレッドプログラムが可能になりました。
マルチスレッド化すると、上の問題に対してさらに違ったアプローチが可能になります。
ここでは、詳細はとりあげないことにします。

 


Top page | Visual Basic&Excel活用研究目次