社内SEの徒然なる日記

Excelで中止機能付きのマクロを作ってみた

中止機能付きのマクロ

実行中のマクロを中止させる方法を考えてみました。
Escキーを押す以外の方法ですよ。

DoEvents関数

通常は、マクロの実行中は画面が固まって何も出来なくなります。
処理を中止させるためには、処理実行中に外部から操作を受け付けさせる必要があるわけで、どうやら、DoEvents関数を使うことで実現できるようです。

Excelヘルプによると、DoEvents関数は「発生したイベントがオペレーティング システムによって処理されるように、プログラムで占有していた制御をオペレーティング システムに渡すフロー制御関数です。」と書いています。
いつものことですが、何言ってるのかさっぱりですね。

まぁ、マクロ実行中に行った操作を反映させることが出来るってことなんでしょうけど、私は「実行中のマクロに隙を作る関数」と理解しました。

事前準備

まず、処理の中断を判断するためのフラグ「gStopFlag」を作成します。
あちことのメソッドから使用するので、Public変数にします。

もう一つ処理を一定時間待機する「K_StopTime」関数を作成しておきます。
この関数は、引数で指定した時間だけ処理を待機します。


Option Explicit

'共通変数「処理中断フラグ」 True:中止、False:続行
Public gStopFlag As Boolean


' 機能 : 指定した秒数処理を停止する。
'
' 引き数 : pStopSecond - 停止する秒数
'
' 機能説明 : マクロの実行を指定した時間停止する。
'
Private Sub K_StopTime(Optional ByVal pStopSecond As Integer)

'停止時刻
Dim myWaitTime As Variant

'引数が省略された場合(または0秒が指定された場合)は、1秒に置き換える
If pStopSecond = 0 Then pStopSecond = 1

'停止時刻を作成します(現在の時刻 + 引数.停止秒数)
myWaitTime = TimeSerial(Hour(Now()), Minute(Now()), Second(Now()) + pStopSecond)

'指定時刻までマクロの実行を停止します。
Application.Wait myWaitTime

End Sub


サンプルメソッド

「macroStart」メソッドと「macroStop」メソッドを作成します。

' 処理メソッド
'
Public Sub macroStart()

'変数
Dim i As Long 'ループカウンタ

'処理中断フラグ = False:続行
gStopFlag = False

'ループ
For i = 0 To 19

'1秒待機します。
Call K_StopTime(1)

'シートに実行件数を表示
Sheet1.Cells(2, 3).Value = i + 1

'5回に一度、中止判定をします。
If i Mod 5 = 0 Then

'OSに制御を返します。
DoEvents

'中止判定
If gStopFlag Then
MsgBox "中止します。" & Chr(10) & Chr(10) & "i = " & i
Exit Sub
End If
End If
Next

'処理終了メッセージ
MsgBox "終了しました。" & Chr(10) & Chr(10) & "i = " & i

End Sub

' 中止メソッド
'
Public Sub macroStop()

'処理中断フラグ = True:中止
gStopFlag = True

End Sub


■ macroStartメソッド

処理自体は簡単な内容です。
For...Next ステートメントで20回処理を繰り返します。

K_StopTime関数で1秒待機。
変数 i が5の倍数になるたびに、DoEvents関数を実行して、変数「gStopFlag」にTrue(中止)が設定されていた場合は処理を中止します。

■ macroStopメソッド

変数「gStopFlag」にTrue(中止)を設定します。

実験開始

適当なシートに、作成した2つのメソッドを動作するボタンを用意します。
開始ボタンには「macroStart」メソッドを、中止ボタンには「macroStop」メソッドを実行するようにします。
イベント

テスト1「中止しない」

まず、中止をしないパターンを試して見ます。
開始ボタンを押して、処理が終了するまで待ちます。

実行結果は、こんな感じです。
きちんと最後まで動作しました。
正常終了

テスト2「中止する」

さて、ここからば本題です。
セルC2には、処理中の変数 i の値を書き出しています。

この値が、7になった時点で「中止」ボタンを押下します。
結果は、以下の通りになりました。
中止

7の時点で「中止」ボタンを押下したのですが、画面上はなにもおこらずに、8,9,10とカウントアップ。
11になった時点で、メッセージボックスが表示されて処理が中止されました。

考察

マクロ実行中、画面がフリーズしているように見えますが、マウスやキーボードの操作は受け付けてくれるようです。DoEvents関数でOSに制御を渡すというのは、この時の操作を反映してくれるってことのようですね。

「中止」ボタンを押下した時に実行される「macroStop」メソッドですが、これは、「中止」ボタンの押下時ではなく、DoEvents関数が実行された時点になります。

macroStart開始 → 「中止」ボタン押下 → DoEvents関数 → macroStart中断 → macroStop実行 → macroStart再開 → 処理中止

こんな感じですかね?

ちなみに、DoEvents関数の発行タイミングを5回に一度にしたのは、この手の関数を連発するのは気持ち悪いからです。
OSの内部動作には疎いのでハッキリ言えないところですが、DoEvents関数が行う「OSに制御を渡す」っていう動作が性能劣化や奇妙な障害の原因になる気がしてならないんですよ。

この感覚、わかってもらえますかね?

次回:Excelで中止機能付きのマクロを作ってみた(フォーム編)
投稿記事の一覧:目次

--- blog end ---

スポンサードリンク

PageTop

コメント


管理者にだけ表示を許可する