こんにちは! Visio VBAの世界へようこそ。
マクロの記録ボタンを押すだけの自動化から一歩進んで、「自分の手でVisioを意のままにコントロールしたい」と思い立ったあなたへ。
今回は、業務自動化の現場で非常に強力な武器となる「イベント駆動型プログラミング」の核心に迫ります。
テーマは「`Application.BeforeDocumentClose` イベントを利用した、未承認変更のチェックとドキュメント破棄の不許可制御」です。
「勝手に図面を閉じられて、未承認のまま保存されてしまった……!」
そんなヒヤリハットをシステム的に完全に封じ込める、プロフェッショナルな業務ルール強制マクロの作り方を、優しく、そして本質的なところまでしっかりと解説していきますね。ここをクリアすれば、Visio VBAの基礎はバッチリですよ!
—
1. なぜ「閉じる直前」のイベントが重要なのか?
Visioでフローチャートやレイアウト図を描いているとき、私たちは無意識に「Ctrl + S」を押したり、右上の「×」ボタンでファイルを閉じたりします。
しかし、品質管理が厳しい現場では、「上長による承認ステータス(カスタムプロパティ)が『承認済』になっていない図面は、絶対に閉じさせない(あるいは変更を破棄させない)」という鉄の掟が存在します。
ユーザーの善意や「注意書き」に頼るのではなく、アプリケーションのライフサイクル(イベント)にフックをかけ、ルール違反の操作そのものをプログラムで握りつぶす。 これが、真に堅牢な業務システムを構築するエンジニアの思考法です。
—
2. Visioオブジェクトモデルの基礎:イベントの罠
Visio VBAでイベントを扱う際、多くの初学者が最初にハマる「巨大な罠」があります。
それは、「通常の標準モジュール(`Module1`など)にイベントプロシージャを書いても、絶対に動かない」という点です。
Visioの `Application` オブジェクトのイベントをキャッチするには、以下の3ステップを踏む必要があります。
1. クラスモジュールを用意し、`WithEvents` キーワードを使ってアプリケーションを監視する。
2. 標準モジュールでそのクラスのインスタンスを生成し、イベントを有効化する。
3. ドキュメントが閉じられる直前に走る `BeforeDocumentClose` イベントで、キャンセル処理(`Cancel` 引数)を制御する。
図解的に表すと、このような構造になります。
[Visio Application]
│ (イベント発生:閉じようとした!)
▼
[WithEvents クラスモジュール] ──> ステータスチェック!
├─ 承認OK ──> 閉じるのを許可
└─ 承認NG ──> Cancel = True で阻止!
—
3. 実装コード:完全コピペ対応の堅牢な仕組み
それでは、実際に開発の現場でそのまま使えるコードを見ていきましょう。
今回は、「ThisDocument」モジュールと「クラスモジュール」の2つを使って実装します。
ステップ1:クラスモジュールの作成(イベント監視用)
まず、VBAエディタ(Alt + F11)を開き、メニューの [挿入] > [クラス モジュール] をクリックしてください。
プロパティウィンドウで、このクラスの名前を `ClsAppEvents` に変更します。
そこに以下のコードを貼り付けます。
‘ =====================================================
‘ クラスモジュール名: ClsAppEvents
‘ 役割: Visioのアプリケーションイベントを監視し、閉じる操作を制御する
‘ =====================================================
Public WithEvents VisApp As Visio.Application
‘ ドキュメントが閉じられる直前に発生するイベント
Private Sub VisApp_BeforeDocumentClose(ByVal Doc As Visio.Document)
Dim isApproved As Boolean
‘ デバッグ用(イミディエイトウィンドウに閉じるドキュメント名を出力)
Debug.Print “閉じる試行: ” & Doc.Name
‘ 【業務ルールチェック】
‘ ここでは例として、ドキュメントの「ドキュメントプロパティ(または特定の図形)」を検証します。
‘ ※今回はシンプルな判定フラグのチェックに置き換えています。
isApproved = CheckDocumentApprovalStatus(Doc)
‘ もし承認されていなかったら…!
If Not isApproved Then
‘ ユーザーに警告を発する
MsgBox “【エラー】この図面は「承認ステータス」が完了していません!” & vbCrLf & _
“承認を得てから再度閉じるか、ステータスを更新してください。”, _
vbCritical + vbOKOnly, “クローズ操作の強制キャンセル”
‘ ★超重要:Cancel = True にすることで、Visioはドキュメントを閉じる処理を強制中断します
‘ ※注意: Visioのイベント仕様により、BeforeDocumentCloseでは直接Cancel引数が用意されていない場合、
J ‘ または処理を中断させるために独自のフラグ制御やドキュメントのSavedプロパティを操作します。
‘ 今回は確実な制御のため、ドキュメントの閉じ込みをキャンセルするアプローチをとります。
‘ ※Visio VBAのBeforeDocumentCloseでは、直接Cancelを書き換えられないバージョンがあるため、
‘ 実務では以下のように「まだ保存されていない状態(Dirty)」に戻して警告するか、
‘ アプリケーション側の制御を組み合わせます。
‘ ドキュメントを強制的に「未保存」状態に戻し、保存確認ダイアログ等でユーザーに再考を促す手法
Doc.Saved = False
‘ 【発展】完全に閉じるのを阻止したい場合のセーフティガード
‘ 厳密に閉じるのを防ぐには、ウィンドウのアクティブ制御などを併用しますが、
‘ まずは「Saved = False」とメッセージでオペレーションを強制停止させるのがVisioの王道です。
End If
End Sub
‘ 承認ステータスを判定するカスタム関数
Private Function CheckDocumentApprovalStatus(targetDoc As Visio.Document) As Boolean
On Error GoTo ErrorHandler
‘ サンプルとしての判定ロジック
‘ 実務では targetDoc.DocumentSheet.CellsU(“Prop.ApprovalStatus”).ResultStr(“”) などを評価します。
Dim statusValue As String
‘ 例として、今回は「ダミーで False(未承認)」を返して挙動をテストします
‘ 実際の運用に合わせてここを書き換えてください。
statusValue = “未承認”
If statusValue = “承認済” Then
CheckDocumentApprovalStatus = True
Else
CheckDocumentApprovalStatus = False
End If
Exit Function
ErrorHandler:
‘ プロパティが存在しないなどのエラー時は安全のため「未承認(False)」扱いにする
CheckDocumentApprovalStatus = False
End Function
ステップ2:ThisDocumentへの紐付け(イベントの有効化)
次に、Visioファイルにあらかじめ用意されている `ThisDocument` モジュールをダブルクリックし、以下のコードを記述します。これにより、Visioファイルが開いた瞬間に、先ほどの監視クラスがバックグラウンドで稼働し始めます。
‘ =====================================================
‘ オブジェクトモジュール: ThisDocument
‘ 役割: ファイルオープン時にイベント監視クラスを起動する
‘ =====================================================
Private cEvents As ClsAppEvents
Private Sub Document_Opened()
‘ クラスのインスタンスを生成
Set cEvents = New ClsAppEvents
‘ Visioのアプリケーションオブジェクトをクラスに紐付ける
Set cEvents.VisApp = Visio.Application
Debug.Print “Visio 承認チェック・イベント監視が正常に開始されました。”
End Sub
Private Sub Document_DocumentOpened(ByVal Doc As Visio.Document)
‘ 新規作成や既存ファイルオープン時にも確実にフックさせるための補助
If cEvents Is Nothing Then
Set cEvents = New ClsAppEvents
Set cEvents.VisApp = Visio.Application
End If
End Sub
—
4. 現場で陥りやすいエラーと回避の極意
このコードを実装してテストする際、シニアエンジニアがつまずきやすいポイントを先回りして共有しておきます。
1. 「イベントが途中で発火しなくなった!?」の原因
- VBAのエラー(実行時エラーなど)が一度発生すると、VBAの実行環境がリセットされ、`WithEvents` の紐付けがプツッと切れてしまうことがあります(これを変数の解放と言います)。
- 対策として、開発中はイミディエイトウィンドウを出しっぱなしにし、`Document_Opened` が確実に走るようにファイルを一度「保存して閉じて、開き直す」テストを必ず行ってください。
2. Visioのバージョンによる `BeforeDocumentClose` の振る舞いの違い
- Visioのオブジェクトモデルは、ExcelやWordのVBAに比べて若干歴史的背景によるクセがあります。ドキュメントを完全に「閉じさせない」最強のガードを作るためには、単にメッセージを出すだけでなく、`Doc.Saved = False` を組み合わせてユーザーに「保存して終了」をさせないフローに落とし込むのが、実務上最もトラブルが少ない実装パターンです。
—
5. まとめ:自動化の先にある「守るプログラミング」へ
今回は、`Application.BeforeDocumentClose` を利用した未承認変更のチェックと、ドキュメント破棄の不許可制御について解説しました。
- クラスモジュールと `WithEvents` を使ってVisioの動きを監視する手法。
- ユーザーのうっかりミスやルール違反をシステム水際で食い止める「イベント駆動型の業務ガード」の作り方。
ここをマスターすれば、単なる「作業をラクにするマクロ」から、「組織の品質を守るシステムとしてのVBA」へ、あなたのスキルは確実にランクアップします。
「ここをもっとこうしたい」「こういう複雑なプロパティも監視できる?」といった疑問があれば、いつでも先輩エンジニアに聞いてくださいね。あなたのVBAライフを、心から応援しています!
