こんにちは! Visioの自動化の世界へようこそ。
マクロの記録ボタンを押して、生成されたコードをそのまま動かしてみたものの、「なぜか意図しないタイミングでエラーが出る」「ユーザーがマウスで図形をドラッグ&ドロップした瞬間にマクロが暴走する」……そんな壁にぶ和れていませんか?
もしあなたが今、Visioの図形操作とVBAの自動化の狭間で頭を悩ませているなら、ここをクリアすればVisio VBAの基本はバッチリです。今日は、プロのエンジニアが現場で必ず実装している「ユーザーの手動操作とVBAの干渉を防ぐ極意」を、優しく、そして深く伝授しましょう。
—
1. なぜVisioのイベントは暴走するのか?(オブジェクトモデルの宿命)
Visio VBAで最も強力、かつ最も扱いづらいのが「イベントハンドラ(`Document_ShapeAdded` など)」です。
ユーザーがステンシルから図形をドラッグ&ドロップした瞬間、Visioの内部では何が起きているでしょうか?
1. ユーザーがマウスで図形をページにドロップする(`ShapeAdded` イベントが発生)
2. VBAのイベントがそれを検知して走り出す
3. VBA側で「お、図形が追加されたな!じゃあ自動で色を変えたり、データを書き込もう」と別の図形操作を行う
4. そのVBAの操作自体が、さらに別のイベントを誘発する……(無限ループの恐怖!)
この「ユーザーの手動操作(スローで重い処理)」と「VBAのプログラム(高速な処理)」が同時に走ることで、Visioがフリーズしたり、予期せぬエラー(実行時エラー)を吐いたりするのです。
これを防ぐためには、「今、Visioの中で何が起きているのか?」をプログラム自身が知る必要があります。
—
2. 救世主:`Application.IsInScope` プロパティとは?
ここで登場するのが、今回の主役である `Application.IsInScope` プロパティ です。
このプロパティは、Visioが現在「どのようなスコープ(文脈・状態)で処理を実行しているか」を判定するためのものです。例えば、「今ユーザーがマウスでドラッグ&ドロップしている最中なのか?」、「VBAから図形を一括生成している最中なのか?」をミリ秒単位で正確に見分けることができます。
主なスコープ定数(一部)
- `visScopeDrop`:ユーザーがドラッグ&ドロップ操作を行っている最中
- `visScopeDelete`:ユーザーが図形を削除している最中
- `visScopePaste`:ペースト操作を行っている最中
つまり、イベントハンドラの最初に「今、ユーザーがドラッグ&ドロップ中(`visScopeDrop`)だったら、このVBAコードは実行せずにスルーしよう!」というガード節(番犬)を置いておけば、干渉を完全に防ぐことができるのです。
—
3. 実践!干渉を防ぐスマートなVBAコード
百聞は一見にしかず。実際のThisDocumentモジュールに記述するコードを見てみましょう。
ここでは、ユーザーがステンシルから図形をドロップしたときのイベントを例に取ります。
Option Explicit
‘ =================================================================
‘ 図形がページに追加された時に発生するイベント
‘ =================================================================
Private Sub Document_ShapeAdded(ByVal Shape As IVShape)
‘ 【重要】現在、ユーザーがドラッグ&ドロップ中であるかを判定
‘ もしドロップ操作の最中であれば、VBA側の干渉を防ぐためにここで処理を抜ける
If Application.IsInScope(visScopeDrop) Then
‘ デバッグ用(イミディエイトウィンドウに出力)
Debug.Print “ユーザーのドラッグ&ドロップ操作を検知しました。VBA処理をスキップします。”
Exit Sub
End If
‘ — ここから下は、VBAプログラムから図形が操作された時だけの処理 —
On Error GoTo ErrorHandler
‘ 例:プログラム側で追加された図形に自動で特定のレイヤーを設定する
‘ Shape.Layer = “SystemGenerated”
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
End Sub
コードの解説
1. `If Application.IsInScope(visScopeDrop) Then`
これが今回のキモです。Visioがユーザーのドラッグ&ドロップという「手動スコープ」にいる間は、`True`を返します。
2. `Exit Sub`
`True`であれば、その場でイベント処理を終了します。これにより、ユーザーの快適なマウス操作を邪魔せず、Visioのクラッシュを防ぐことができます。
—
4. プログラミング初学者が陥りやすい罠とアドバイス
よくある間違いとして、「すべてのイベントを `Application.EnableEvents = False` で止めればいいや」と考えてしまうケースがあります。
確かにExcel VBAなどでは一般的ですが、Visioにおいてこれをやると、ユーザーが手動で行った操作のイベントまで完全に遮断されてしまい、アプリ全体がまともに動かなくなるという副作用があります。
だからこそ、Visioでは「全体のイベントを止める」のではなく、`IsInScope` を使って「今、誰がこの動作を引き起こしているのか(ユーザーか、プログラムか)」をスマートに識別するのがプロの作法なのです。
—
まとめ:Visio VBAを掌握する
いかがでしたか? `Application.IsInScope` を知ることで、あなたは単なる「マクロの記録の延長」から、堅牢で実用的な業務システムを構築する「プロフェッショナルなVisio開発者」へとステップアップしました。
- ユーザーの動きとVBAがバッティングしたら、まずスコープを疑う
- `IsInScope(visScopeDrop)` でガード節を作る
この2つを覚えておけば、現場の現場で「なぜか動かない」と頭を抱えることはもうありません。ぜひ、あなたの開発するVisioツールにこの知見を取り入れて、圧倒的に安定した自動化を実現してくださいね。
それでは、次回の高度なVisio自動化の世界でお会いしましょう!バッチリ使いこなしてくださいね。
