皆さんは、VBAでDoEnents関数を使って処理をキャンセルする方法を知っていますか?
キャンセルボタンなどを実装するときなど、処理の途中で止めたいケースはありますよね。そこで今回は、DoEvents関数の基礎的な使い方といった基礎的なことから、
- サンプルコードを使った具体的な使い方
 - 処理速度を保ちつつDoEventsを実行する方法
 - 合わせて覚えると便利なユーザーフォームの作り方
 
といった応用的な方法まで、徹底的に解説します!
DoEvents関数の使い方とは
DoEvents関数は、処理を途中で止めてOSに処理を渡すための関数です。たとえば、ループ処理中にキャンセルボタンを押す場合などに使います。以下のように書くことで、処理を途中で止めてOSに処理を渡すことができます。
Sub Test()
  'ループ処理
  Dim i As Integer
  For i = 0 to 10000
    DoEvents
    'メイン処理
  Next i
End Sub
この処理中にキャンセルボタンを押した場合はOSに処理が移る → キャンセルボタンのクリックが実行されるため、処理を途中で止めることができます。
サンプルコード
次に、具体的なサンプルコードをもとに、使い方を解説します。

ユーザーフォームのコードサンプル:
Dim judgeStop As Boolean 'グローバル変数
'実行ボタンクリック時の処理
'
Private Sub CommandButton1_Click()
  judgeStop = False
  Dim i As Integer
  Dim j As Integer
  For i = 0 To 10000
    For j = 0 To 10000
      'キャンセルが来たら処理を途中で停止
      DoEvents
      ActiveSheet.Range("A1").Value = "i:" & i & vbCrLf & _
                                       "j:" & j
      'キャンセルボタンクリック時は処理を止める
      If judgeStop = True Then
        Exit Sub
      End If
    Next j
  Next i
End Sub
'キャンセルボタンクリック時の処理
'
Private Sub CommandButton2_Click()
  'キャンセルボタンクリック判定を更新
  judgeStop = True
  '画面を閉じる
  Unload UserForm1
End Sub
'ユーザーフォーム実行時の初期化処理
'
Private Sub UserForm_Initialize()
  ComboBox1.AddItem "ループ処理1"
  ComboBox1.AddItem "ループ処理2"
  ComboBox1.AddItem "ループ処理3"
  ComboBox1.AddItem "ループ処理4"
  ComboBox1.Value = "ループ処理1"
End Sub

CommandButton1_Clickで実行ボタンクリック時の処理、CommandButton2_Clickでキャンセルボタンクリック時の処理を書いています。
キャンセルボタンのクリック判定に使うために、キャンセルボタンクリック時にグローバル変数(judgeStop)をTrueに変更し、実行ボタンクリック時のループ処理でjudgeStopがTrueだったときのみ処理を停止しています。
このように、DoEvents関数 + Subをまたいで使えるグローバル変数を組み合わせると簡単にキャンセル処理を作ることができます。グローバル変数については以下で詳しく解説しているので、気になる方は見てみてくださいね!
            
                
                    
DoEvents関数で処理が重たくなった時に試す方法
DoEvents関数は他の処理に影響が出ないか調べてからOSに処理を渡すため、処理によっては実行速度が落ちてしまうことがあります。そのため、GetInputState関数とあわせて使うのがおすすめです!GetInputState関数はイベントキューに待機中のイベントのみ調べることができます。
そのため、イベントが発生しているときだけOSに制御を渡すことができるようになり、処理時間を大幅に短縮することができます。
サンプルコード:
Private Declare Function GetInputState Lib "USER32" () As Long
Sub Test()
  Dim i As Integer
  Dim j As Integer
  'GetInputState関数でチェック
  If GetInputState() Then
    For i = 0 To 10000
      For j = 0 To 10000
        DoEvents
        'メインのループ処理
      Next j
    Next i
  End If
End Sub
処理速度が遅くなってしまった場合は、こちらも合わせて覚えておくと便利ですね。
補足:合わせて覚えると便利なユーザーフォームの作り方
補足ですが、今回のサンプルコードで紹介した画面は、ユーザーフォームを使って作ることができます。ユーザーフォームの使い方については以下で詳しく解説しているので、気になる方は見てみてくださいね!
            
                
                    
まとめ
今回は、VBAでDoEventsを使って処理を途中で止める方法を解説しました。ループ処理中にキャンセルボタンで処理を止めるケースはよくあります。使い方も簡単なので、ぜひ使ってみてくださいね!
  





