Excel

【ExcelVBA】WaitまたはSleepで一時停止する方法と使い分け

更新日:2023/12/01

ExcelでVBAコードの処理を一定時間停止するときは、WaitメソッドまたはSleep関数を使用します。
今回はこの二つについて特徴と使い方をお伝えします。

 

WaitメソッドとSleep関数の違い

WaitメソッドとSleep関数は、処理を一時的に停止して一定時間経過後に処理を再開するときに使用します。

WaitとSleepは動作については、大きな違いはありません。
しかし使用できる場面と使用できない場面があるので、それぞれの違いを知って適切に使い分ける必要があります。

Waitメソッドの特徴

WaitメソッドはApplicationオブジェクトのメソッドで、実行時に再開する時刻を指定します。
停止中はExcelの操作ができません。
ただし、Excel内部での印刷処理や計算などは行われます。

停止中にEscキーなどの処理を中断するキーを押すと、一時停止が解除されて次の処理に移ります。
これはデメリットと言えますが、Application.EnableCancelKeyプロパティと併用することで、中断キーの影響を回避できます。

Sleep関数の特徴

Sleep関数は、Windowsが持っている機能をVBAで呼び出します。
そのためMacなどのWindows以外のOSでは使用できません。

Sleep関数は、待機時間を指定します。
指定時間経過まで、中断できません。

推奨はWaitメソッド

Sleep関数はWindowsでのみ使用可能で、その他のOSで使用すると実行時エラーで処理が中断するなどのデメリットがあります。
実際にはMac等でも似た機能を呼び出すことができますが、実装後にMac等の機器を用意して検証する必要があります。
そこまでして使用するメリットはSleep関数にありません。

そのため、特段の理由がなければWaitメソッドの使用をおススメします。

 

Waitメソッドの使い方

Waitメソッドは、処理停止後に再開する時刻を指定します。
構文は次のようになっています。

result = Application.Wait( 再開する時刻 )

規定時間まで待機できた場合は、trueが返ります。
中断された場合はfalseが返ります。

秒単位のWait

再開する時刻は、基本的には、現在時刻に停止する時間を秒単位で加算します。
例えば5秒間停止するときは、次のようになります。

Application.Wait Now() + TimeValue("00:00:05")

Now()とTimeValue()はMsgbox等で確認すると日付の文字列が表示されるので、加算するのは不思議な感じがしますね。
少し分かりにくいですが、Now()とTimeValue()は内部でDateとして処理する値を格納しているVariant型(Variant/Date)を返しています。
文字列ではないので、加算できるのです。

ミリ秒単位のWait

Waitはミリ秒単位でも実行できます。
例えば500ミリ秒間停止するときは、次のようになります。

Application.Wait [Now()] + 500 / 86400000

Variant/Dateを [ ] で囲むと、Variant/Double型の値を取得できます。
この値は整数部が日数なのでミリ秒を加算するときは、24(時間) × 60(分) × 60(秒) × 1000(ミリ秒) = 86,400,000 で割る必要があります。

コード例

Application.waitの中断を抑制、または中断の確認をおこなう場合、関数化した方が使いやすいです。
今回は、次のような関数を作成しました。

' 一定時間停止する関数
' millisecond: 停止する時間(ミリ秒)
' enableCancelKey: Escキー等で中断するかどうか true 中断する
' confirm: 中断時確認するかどうか true 確認する
'          ※enableCancelKeyがtrueの時有効
'          ※Application.enableCancelKeyがxlDisabledでないとき有効
Sub wait(millisecond As Integer, _
    Optional enableCancelKey As Boolean = True, _
    Optional confirm As Boolean = False)

    Dim returnTime
        ' Wait終了時刻を算出
    returnTime = [ Now() ] + millisecond / 86400000
    
    Dim result

    result = Application.wait(returnTime)
   
    While result = False
        DoEvents
        If enableCancelKey = True Then
        
            If confirm = True Then ' 中断確認
                If MsgBox("中断キーが押されました。中断しますか?" _
                    , vbQuestion + vbYesNo) = vbYes Then
                    End
                End If
            Else
                End
            End If
        End If
        result = Application.wait(returnTime)
    Wend
    
End Sub

Application.waitの戻り値がfalseのとき、再度Application.waitを呼び出しています。
ただしEscキーで中断すると、次回以降のApplication.waitが待ち時間ゼロで終了します。
DoEventsを呼び出すことで、この問題を対処できます。

次のコードは、作成した関数を実行するサンプルです。
5000ミリ秒停止中にキーで中断された場合、確認ダイアログを表示します。

Wait後は、イミディエイトウィンドウに停止時間が表示されます。

Sub waitTest()
    Dim t
    t = Timer
    Debug.Print "開始"
    Call wait(5000, True, True)
    Debug.Print Timer - t & "秒"
End Sub

なおEscキーを押しっぱなしのときは、Application.wait以外のコードで中断します。

中断確認が必要なければ、次のようにApplication.enableCancelKey に xlDisabled をセットします。
これでキー入力による中断が回避されます。

Sub wait(millisecond As Integer, _
    Optional enableCancelKey As Boolean = True)

    Dim key
    key = Application.enableCancelKey ' 現在の値を退避

    If enableCancelKey = False Then
        Application.enableCancelKey = xlDisabled ' キーによる中断を無効化
    End If

    result = Application.wait([ Now() ] + millisecond / 86400000)
    Application.enableCancelKey = key ' 退避した値を戻す
    
    If result = False Then ' waitが中断された
        End
    End If
End Sub

 

Sleep関数の使い方

Sleep関数は、Declareステートメントで参照設定をおこないます。

#If VBA7 Then
    Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#Else
    Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If

VBA7(Excel2010以降)は、PtrSafe というキーワードが必要なので条件分けしてあります。

このコードで参照されたSleep関数の構文は、次のようになります。

Sleep( 停止時間(ミリ秒) )

次のコードはSleep関数の使用例です。
Sleep後に、停止していた時間をイミディエイトウィンドウに表示されます。

Sub sleepTest()
    Dim t
    t = Timer
    Debug.Print "開始"
    
    Sleep 5000
    
    Debug.Print Timer - t & "秒"
End Sub

更新日:2023/12/01

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。