こんにちは!Visio VBAの世界へようこそ。
マクロの記録ボタンを押してコードを眺めるだけの日々は、もう卒業です。ここからは、Visioのオブジェクトモデルを自在に操り、業務を完全に自動化する「プロの領域」へ踏み込んでいきましょう。
今回は、Visio VBAにおいて避けて通れない「イベント処理の罠」と、それを美しく回避する極意を伝授します。
ここをクリアすれば、あなたの書くマクロは「おもちゃ」から「堅牢な業務システム」へと劇的に進化します。しっかりついてきてくださいね!
—
1. なぜVisioのイベント処理は「暴走」するのか?
Visio VBAでは、図形が動かされたり、ページが追加されたりした瞬間にコードを走らせる「イベントハンドラー」という強力な機能があります。
例えば、「ユーザーが図形を動かしたら、自動的にログを記録する」「特定のシェイプのテキストが変わったら、連動して別の処理をする」といった自動化です。
ここで、こんな状況を想像してください。
1. ユーザーが図形を移動した。
2. イベントが発火し、VBAコードが走って図形をさらに加工した。
3. ユーザーが「あ、今の移動ミスった!Ctrl + Z(元に戻す:Undo)しよう」と押した。
4. ここで大惨事が起きます。
Visioにとって「Undo(元に戻す)」や「Redo(やり直し)」も、内部的には「図形を別の位置に変更するイベント」として扱われます。
つまり、ユーザーがUndoした瞬間、VBAがそれを「新たな変更」と勘違いして再び割り込み、無限ループに突入。最終的にVisioごとフリーズ、あるいはクラッシュ……これが、開発者を絶望の淵に落とす「イベントの無限ループ地獄」です。
—
2. 救世主:`Application.IsUndoingOrRedoing` とは?
この恐怖の無限ループをスマートに防ぐために用意されているのが、Visioのアプリケーションオブジェクトが持つプロパティ、`IsUndoingOrRedoing` です。
> `Application.IsUndoingOrRedoing`
> 現在、ユーザーが「元に戻す(Undo)」または「やり直し(Redo)」の最中であるかどうかを `True` / `False` で返す読み取り専用のプロパティ。
仕組みはとてもシンプルです。
イベントが発生したときに、「今、ユーザーがUndoしてる最中じゃないよね?」とこのプロパティでガードをかけ、もし`True`(Undo中)であれば、VBAの独自処理を実行せずに即座に抜ける(Exit)ようにするのです。
これを知っているだけで、あなたの書くコードの安全性はプロ基準に達します。
—
3. 実践!安全なイベントハンドリングの実装コード
それでは、実際にこの仕組みを組み込んだ安全なイベント処理のコードを見てみましょう。
今回は、ドキュメントレベルのイベント(`DocumentEvent`)を監視し、図形が変更されたときに安全に処理を行うテンプレートをご紹介します。
ステップ1:クラスモジュールの作成(例:`clsEventSink`)
まずは、イベントを受け取るためのクラスモジュールを作成します。
‘ =================================================================
‘ クラスモジュール名: clsEventSink
‘ 概要: Visioのイベントを安全にキャッチするクラス
‘ =================================================================
Public WithEvents VisApp As Visio.Application
‘ 図形が変更されたときに走るイベント
Private Sub VisApp_ShapeChanged(ByVal Shape As IVShape)
‘ 【極意】今、Undo/Redoの最中なら、処理を一切行わずに即終了する!
If VisApp.IsUndoingOrRedoing Then
Exit Sub
End If
‘ — ここから下が、通常の変更時にのみ実行したい安全な処理 —
On Error GoTo ErrorHandler
‘ 例:変更された図形の名前を出力ウィンドウに表示する
Debug.Print “図形が変更されました: ” & Shape.Name
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
End Sub
ステップ2:標準モジュールでのイベント有効化
次に、標準モジュールから上記のクラスをアプリケーションにアタッチします。
‘ =================================================================
‘ 標準モジュール
‘ 概要: イベント監視の開始・停止を制御する
‘ =================================================================
Dim cEventSink As clsEventSink
Public Sub StartMonitoring()
‘ すでに監視中でなければ、イベントのフックを開始
If cEventSink Is Nothing Then
Set cEventSink = New clsEventSink
Set cEventSink.VisApp = Visio.Application
MsgBox “Visioの安全なイベント監視を開始しました。”, vbInformation
Else
MsgBox “すでに監視は稼働中です。”, vbExclamation
End If
End Sub
Public Sub StopMonitoring()
‘ 監視を終了
Set cEventSink = Nothing
MsgBox “イベント監視を停止しました。”, vbInformation
End Sub
—
4. プログラミング初学者への温かいアドバイス
最初は「クラスモジュール? `WithEvents`?」と難しく感じるかもしれません。でも、安心してください。ここをクリアすれば、あなたは単なる「マクロの記録者」ではなく、「Visioアプリケーションのアーキテクト」の仲間入りです。
実務でVisioの自動化ツールを納品するとき、ユーザーは必ず「うっかりCtrl+Zを押す」という想定外の操作をします。そのときにツールが耐えられるかどうかは、この `IsUndoingOrRedoing` を知っているかどうかにかかっています。
「あ、危ないところだった。先輩の教え通り、ここでしっかりガードしておこう」
そう思っていただければ、この記事を書いた甲斐があります。
ぜひ、あなたの開発するVisioツールにこの知見を取り入れて、堅牢で美しい自動化を実現してくださいね。応援しています!
