【VBA】マクロを時間差で実行・繰り返し実行する方法 (OnTime, GetTickCount)

目次

はじめに

VBAで、「5分後に自動でファイルを保存したい」「10秒ごとにシートの値を更新したい」といった、時間を起点とした処理を実装したい場面は多くあります。また、より高度な使い方として、図形を滑らかに動かすようなアニメーションを作成したい場合もあります。

VBAには、このような時間関連の処理を実装するための仕組みがいくつか用意されています。この記事では、用途に応じて3つの異なるタイマー処理の実装方法を解説します。

  1. 指定した時間後に、マクロを一度だけ実行する方法
  2. 一定間隔で、マクロを繰り返し実行する方法
  3. 1秒以下の高速な間隔で、処理を繰り返し実行する方法

1. 指定した時間後にマクロを一度だけ実行する (Application.OnTime)

Application.OnTime メソッドは、指定した時刻に特定のマクロを実行するように予約(スケジュール)する機能です。Now(現在時刻)と TimeValue(時間)を組み合わせることで、「今から〇秒後」という指定ができます。

サンプルコード

' このマクロを実行すると、10秒後に "DisplayMessage" が実行される
Sub ScheduleSingleExecution()
    Dim scheduledTime As Date
    scheduledTime = Now + TimeValue("00:00:10") ' 現在時刻の10秒後
    
    ' OnTimeメソッドで、実行時刻と実行するマクロ名を予約
    Application.OnTime EarliestTime:=scheduledTime, Procedure:="DisplayMessage"
    
    MsgBox "10秒後にメッセージが表示されます。"
End Sub

' 予約されて実行されるマクロ
Sub DisplayMessage()
    MsgBox "スケジュールされたタスクが実行されました!"
End Sub

解説: Application.OnTimeEarliestTime 引数に未来の時刻を、Procedure 引数に実行したいマクロ名を文字列で渡します。


2. 一定間隔でマクロを繰り返し実行する (Application.OnTime)

Application.OnTime は、自分自身を再度呼び出すように予約することで、繰り返し処理を実現できます。処理を停止させるためのカウンター変数や条件分岐を設けることが重要です。

サンプルコード

' --- モジュールの先頭に記述 ---
Private nextRunTime As Date
Private executionCount As Long

' 繰り返し処理を開始する
Sub StartRepeatingTask()
    executionCount = 0
    Call UpdateCellPeriodically ' 最初の1回を実行
End Sub

' 3秒ごとにセルを更新する処理
Sub UpdateCellPeriodically()
    ' 実行回数が5回に達したら終了
    If executionCount >= 5 Then
        MsgBox "繰り返し処理を終了しました。"
        Exit Sub
    End If
    
    executionCount = executionCount + 1
    Range("A1").Value = executionCount & "回目の更新 (" & Time & ")"
    
    ' --- 3秒後に、このマクロ自身を再度実行するように予約 ---
    nextRunTime = Now + TimeValue("00:00:03")
    Application.OnTime EarliestTime:=nextRunTime, Procedure:="UpdateCellPeriodically"
End Sub

解説: UpdateCellPeriodically マクロの最後に、3秒後の自分自身を OnTime で予約しています。これにより、3秒ごとに処理が繰り返されます。executionCount が5に達すると、予約をせずに Exit Sub するため、繰り返しが停止します。


3. 1秒以下の高速な間隔で処理を実行する (Windows API)

Application.OnTime の精度は秒単位のため、滑らかなアニメーションのような、1秒以下の高速な繰り返し処理には不向きです。このような場合は、Windows APIの GetTickCount 関数を利用します。

サンプルコード

'--- モジュールの先頭に記述 (API関数の宣言) ---
' 64bit/32bit両対応
#If VBA7 Then
    Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
#Else
    Declare Function GetTickCount Lib "kernel32" () As Long
#End If

'--- モジュールレベルの変数を宣言 ---
Private lastTick As Long
Private loopCounter As Long

' 100ミリ秒ごとに図形を動かすアニメーションを開始
Sub StartShapeAnimation()
    Const FRAME_INTERVAL As Long = 100 ' 実行間隔(ミリ秒)
    Const MAX_LOOPS As Long = 50      ' ループの最大回数
    
    Dim targetShape As Shape
    Set targetShape = ActiveSheet.Shapes(1)
    
    loopCounter = 0
    lastTick = GetTickCount ' 開始時刻を記録
    
    Do While loopCounter < MAX_LOOPS
        ' 前回の実行から指定した時間が経過したかチェック
        If GetTickCount > lastTick + FRAME_INTERVAL Then
            '--- 実行したい処理 ---
            targetShape.Left = targetShape.Left + 10
            
            '--- 時刻とカウンターを更新 ---
            lastTick = GetTickCount
            loopCounter = loopCounter + 1
        End If
        
        ' ExcelがフリーズしないようにCPUを解放
        DoEvents
    Loop
    
    MsgBox "アニメーションを終了しました。"
End Sub

解説:

  • GetTickCount: PCが起動してからの経過時間をミリ秒単位で返すAPI関数です。
  • Do While ... Loop: ループの中で GetTickCount の値を絶えず監視し、前回処理を実行した時刻 (lastTick) から指定した間隔(FRAME_INTERVAL)が経過した瞬間に、次の処理を実行します。
  • DoEvents: 高速なループ処理中にExcelが応答なしになるのを防ぐためのおまじないです。

まとめ

今回は、VBAで時間差処理や繰り返し処理を実装する3つの方法を解説しました。

  • Application.OnTime: 秒単位の単純な遅延実行や、低頻度の繰り返し処理に最適。
  • GetTickCount + Do...Loop: ミリ秒単位の高速な繰り返し処理(アニメーションなど)に最適。

用途に応じてこれらのテクニックを使い分けることで、単なる一括処理だけでなく、より高度で動的なマクロを作成することができます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次