マクロ記録の先へ。Visio VBAで「設計の秩序」を自動化する:レイヤー未設定シェイプの検知と整理
こんにちは。業務自動化の世界へようこそ。
「マクロの記録」ボタンを押して、自分の操作をコードに変換することからVBAの旅は始まります。でも、もしあなたが「もっと複雑なことをしたい」「バラバラになった図面を、一瞬でルール通りに整えたい」と願うなら、今こそ「オブジェクトの構造」という本質的な概念に踏み込む時です。
今日、私があなたに伝授するのは、単なるコードの書き方ではありません。
大規模な図面(ダイアグラム)において、メンテナンス性を劇的に向上させるための「秩序の自動生成」という考え方です。
具体的には、「どのレイヤーにも属していない、迷子のシェイプ」を特定し、自動的に『未分類』レイヤーへ隔離するツールを構築していきます。
なぜ「レイヤー管理」が重要なのか?
大規模なシステム構成図やネットワーク図を想像してみてください。
「サーバー層」「クライアント層」「ネットワーク機器層」……。これらがレイヤー分けされていれば、特定の層だけを非表示にしたり、一括で印刷したりすることが容易です。
しかし、誰かが新しいシェイプをポンと置いたとき、レイヤー設定を忘れてしまうことがあります。これが積み重なると、図面は「制御不能なカオス」へと変貌します。
「ルールに従っていないものを、自動で見つけて、正しい場所に収める」
このロジックをマスターすることは、エンジニアとして「自動化の神髄」に触れる第一歩なのです。
核心となるロジック:オブジェクトの階層を理解する
このツールを作るために、私たちはVisioの「オブジェクトモデル」という地図を読み解く必要があります。
1. Page(ページ): 図面の舞台です。
2. Layer(レイヤー): 図面上の「属性」の集合です。ページに紐づいています。
3. Shape(シェイプ): 実際に描かれている図形です。
4. Shape.LayerCount: これが今回の鍵です。シェイプが現在いくつのレイヤーに所属しているかを数値で返します。
「もし `LayerCount` が `0` なら、そのシェイプは迷子である」
このシンプルな判断を、ページ内の全シェイプに対して高速に実行していきます。
実装:未分類シェイプ整理ルーチン
それでは、プロフェッショナルのコードを見ていきましょう。単に動くだけではなく、エラーに強く、パフォーマンスを意識した構成にしています。
Option Explicit
''' <summary>
''' ページ内の全シェイプを走査し、レイヤー未設定のものを「未分類」レイヤーへ移動させる
''' </summary>
Sub OrganizeUnclassifiedShapes()
Dim targetPage As Visio.Page
Dim targetLayer As Visio.Layer
Dim shp As Visio.Shape
Dim unclassifiedLayerName As String
Dim layerExists As Boolean
Dim count As Integer
' --- 設定領域 ---
unclassifiedLayerName = "未分類"
Set targetPage = ActivePage ' 現在開いているページを対象にする
' ----------------
' 処理中の画面更新を停止してパフォーマンスを向上させる(プロの作法です)
Application.ScreenUpdating = False
On Error GoTo ErrorHandler
' 1. 「未分類」レイヤーが存在するか確認し、なければ作成する
layerExists = False
For Each targetLayer In targetPage.Layers
If targetLayer.Name = unclassifiedLayerName Then
layerExists = True
Exit For
End If
Next targetLayer
If Not layerExists Then
Set targetLayer = targetPage.Layers.Add(unclassifiedLayerName)
Debug.Print "レイヤー '" & unclassifiedLayerName & "' を新規作成しました。"
Else
Set targetLayer = targetPage.Layers(unclassifiedLayerName)
End If
' 2. ページ内の全シェイプを走査
count = 0
' 重要:Page.Shapes は「直下のシェイプ」のみを指す場合があります。
' グループ化された中のシェイプまで確実に捕まえたい場合は、
' 再帰的に走査するか、AllShapesコレクションを使用するのが定石です。
For Each shp In targetPage.AllShapes
' シェイプが一つもレイヤーに属していない(LayerCount = 0)場合
If shp.LayerCount = 0 Then
' 指定したレイヤーに追加
shp.AddLayer targetLayer
count = count + 1
End If
Next shp
' 3. 結果の報告
Application.ScreenUpdating = True
If count > 0 Then
MsgBox count & " 個のシェイプを '" & unclassifiedLayerName & "' レイヤーに移動しました。", vbInformation, "整理完了"
Else
MsgBox "未分類のシェイプは見つかりませんでした。", vbInformation, "確認完了"
End If
Exit Sub
ErrorHandler:
Application.ScreenUpdating = True
MsgBox "予期せぬエラーが発生しました:" & vbCrLf & Err.Description, vbCritical, "エラー"
End Sub
ここがプロの視点!設計のポイント解説
コードをただコピペするだけでは、あなたの成長は止まってしまいます。なぜこのような書き方をしたのか、その意図を解説します。
① `AllShapes` の選択(重要!)
初心者の方は `targetPage.Shapes` を使いがちです。しかし、`Shapes` コレクションは「ページ直下のシェイプ」しか見てくれません。もしシェイプが「グループ化」されていたら、その中身(子要素)は見逃してしまいます。
`AllShapes` を使うことで、グループの奥深くに隠れた迷子のシェイプまで、一網打尽にできるのです。
② `Application.ScreenUpdating = False`
大量のシェイプを操作する場合、Visioが一つ一つの移動を画面に描画しようとすると、動作が極端に重くなります。
「描画を止めて、メモリ上で計算を終わらせてから、最後にパッと見せる」
これは、業務自動化エンジニアが必ず守るべき、パフォーマンス向上の鉄則です。
③ エラーハンドリングの重要性
図面が保護(Protect)されていたり、特殊なオブジェクトが含まれていると、マクロは途中で止まってしまいます。`On Error GoTo ErrorHandler` を記述しておくことで、万が一の際にも「画面更新を再開させてから、エラー内容を丁寧に伝える」という、ユーザーに優しい挙動を実現しています。
陥りやすいエラーと対策
このツールを使っていると、次のような壁にぶつかるかもしれません。
- 「アクセスが拒否されました」というエラー
- 原因: ページやシェイプが「保護(Protect)」されている可能性があります。
- 対策: `targetPage.Protect = False` を実行するか、図面の保護設定を確認してください。
- 「レイヤー名が重複しています」
- 原因: 既に同じ名前のレイヤーがあるのに、`Layers.Add` を実行しようとした。
- 対策: 今回のコードのように、必ず「存在チェック(`If Not layerExists`)」を挟むように設計しましょう。
まとめ:一歩ずつ、アーキテクトへ
お疲れ様でした。これであなたは、「ただマクロを記録する人」から、「図面の構造を制御するエンジニア」へと一歩踏み出しました。
今回学んだ「コレクションの走査」「条件によるオブジェクトの状態判定」「エラーとパフォーマンスへの配慮」は、Visioに限らず、あらゆるプログラミングに通じる普遍的な知見です。
このツールをベースに、「未分類のシェイプの色を赤に変える」機能や、「特定の名前を持つシェイプを別レイヤーに分ける」機能など、自分なりの拡張を加えてみてください。
その試行錯誤こそが、あなたを伝説のエンジニアへと導く唯一の道なのです。
応援していますよ。
