DoEvents

にメンテナンス済み

VBA を使用することで、Excel や Access といったアプリケーションの操作を自動化することができます。 本記事では、VBA におけるDoEventsの構文と使い方、活用シーン、注意点について説明します。また、指定時間待機する方法についても解説します。

DoEventsとは

DoEventsは、VBA(Visual Basic for Applications)において、実行中のプロシージャを一時的に中断し、OS に処理を渡して待機中のイベント(画面の再描画やキー入力、マウス操作など)を処理させるための関数です。 これを使用することで、長時間実行されるマクロが画面描画やユーザー操作をブロックするのを防げます。

正確には戻り値(Integer。Excel などでは常に 0 を返します)を持つ関数ですが、VBA ではほとんどの場合、戻り値を使わずDoEventsと単独で記述します。

DoEventsの構文

DoEvents

引数は取らず、単純に呼び出すだけで機能します。

DoEventsの使い方

基本的な使い方

Private Sub LongRunningProcess()
    Dim i As Long
    For i = 1 To 100000
        ' 長時間かかる処理
        Cells(i, 1).Value = i
        DoEvents ' 他のイベントを処理するための呼び出し
    Next i
End Sub

この例では、ループ内でDoEventsを呼び出し、処理中に他のイベントが処理されるようにしています。ただし、DoEventsは呼び出すたびにオーバーヘッドが発生するため、毎回呼び出すとマクロの実行時間が大幅に延びることがあります。

UI の応答性を保つ

ユーザーが Excel の UI と相互作用できるようにするためにDoEventsを使用する例を示します。

Private Sub MaintainUIResponsiveness()
    Dim i As Long
    For i = 1 To 100000
        Cells(i, 1).Value = i
        If i Mod 1000 = 0 Then DoEvents ' 1000回ごとに他のイベントを処理
    Next i
End Sub

ここでは、iの値が 1000 の倍数になるたびにDoEventsを呼び出すことで、処理速度への影響を抑えつつ UI が応答し続けるようにしています。

DoEventsの活用シーン

長時間実行されるマクロ

長時間実行されるマクロがユーザーインターフェースをブロックするのを防ぎます。例えば、大量のデータを処理する場合や複雑な計算を行う場合に有効です。

ユーザーの中断を許可する場合

ユーザーが中断ボタンなどを使ってマクロの実行を停止できるようにする場合にもDoEventsが役立ちます。

' Declareはモジュールの先頭(宣言セクション)に記述する
' 64bit版・32bit版どちらでも動作する宣言
#If VBA7 Then
    Private Declare PtrSafe Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
#Else
    Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
#End If

Private Sub AllowUserInterrupt()
    Dim i As Long
    For i = 1 To 100000
        Cells(i, 1).Value = i
        DoEvents
        If UserWantsToStop() Then Exit Sub
    Next i
End Sub

Function UserWantsToStop() As Boolean
    ' ここでは例として、Escキーが押されているかを判定する
    UserWantsToStop = ((GetAsyncKeyState(vbKeyEscape) And &H8000) <> 0)
End Function

指定時間待機する方法

DoEventsを応用して、指定時間待機することも可能です。以下はその例です。

Sub ResponsiveWait(ByVal seconds As Single)
    Dim endTime As Double
    endTime = Now + seconds / 86400 ' 1日=86400秒
    Do While Now < endTime
        DoEvents
    Loop
End Sub

Sub TestResponsiveWait()
    ResponsiveWait 5 ' 5秒間待機
End Sub

この方法では、待機中も他のイベントを処理するため、UI の応答性が保たれます。なお、Timer関数を使う方法は午前 0 時をまたぐと値が 0 に戻るため、日付をまたぐ可能性がある場合は上記のようにNowを使うと安全です。ただし、Nowの精度は 1 秒程度のため、1 秒未満の短い待機には向きません。また、待機中は CPU を消費し続ける点に注意してください。

VBA で指定時間待機する方法として、DoEventsに限らずいくつかの方法があります。他の方法についても知りたい場合は、以下の記事を参照してください。

指定時間待機する
VBAで指定時間だけ待機する方法として、Windows APIのSleep、ExcelのApplication.Wait、DoEventsを使った待機ループを比較します。それぞれの特徴、注意点、使い分けを解説します。

DoEvents使用時の注意点

  • 再入に注意: DoEvents中にユーザーがボタンを再度押すと、同じマクロが二重に実行されることがあります。実行中はボタンを無効化するか、フラグ変数で多重実行を防いでください。
  • 速度低下: 呼び出しのたびにオーバーヘッドが発生するため、一定回数ごとに呼び出すようにしましょう。
  • 画面更新の抑制との併用: Application.ScreenUpdating = Falseとしている間は画面が更新されません。進捗を表示したい場合はApplication.StatusBarを併用し、処理後にApplication.StatusBar = Falseで元に戻してください。

まとめ

この記事では、VBA におけるDoEventsの基本的な使い方と活用シーンについて解説しました。 DoEventsを適切に使用することで、マクロの実行中でもユーザーインターフェースの応答性を保つことができ、より使いやすいアプリケーションを作成することができます。

#vba #doevents #関数 #ウェイト