Visio VBAの深淵:グループ化された「迷宮」を再帰的に走査し、完全制御する技術
Visioのオブジェクトモデルは、一見すると直感的だ。`Page`があり、その中に`Shapes`がある。だが、一度「グループ化」という概念が持ち込まれると、多くのエンジニアがその階層構造の迷宮に足を取られる。
`Shape.Shapes`プロパティは、グループ化されたシェイプに対してのみ有効なコレクションを返す。この「入れ子」構造を愚直なループで処理しようとすれば、必ず破綻する。本稿では、グループ化された複雑なシェイプ階層を、再帰アルゴリズムを用いていかに「エレガントかつ堅牢に」制御するか、その知見を共有する。
—
1. なぜ「再帰」が唯一の正解なのか
Visioにおいて、グループ化されたシェイプは `Type` プロパティが `visTypeGroup` を返すが、その中身(`Shapes`コレクション)を走査しなければ、深層にある孫シェイプや曾孫シェイプには到達できない。
ここで、多くの初学者は多重ループを記述しようとする。しかし、グループの深さが未知数である場合、多重ループは保守性を殺す。再帰(Recursion)こそが、動的な階層構造を突破する唯一の解法である。
陥りやすい罠:メモリ管理の怠慢
Visioのオブジェクトモデルは、COM(Component Object Model)のラッパーである。`For Each` でオブジェクトを生成するたびに、スタックやヒープに参照が蓄積される。再帰処理中に明示的な解放(`Set object = Nothing`)を行わなければ、メモリリークは避けられない。特に大規模な組織図やネットワーク図を操作する場合、これがパフォーマンス低下のトリガーとなる。
—
2. 実装:再帰的走査による安全なプロパティ操作
以下に、グループ階層を深く掘り下げ、特定のIDを持つ子シェイプのテキストを一括で書き換えるプロシージャを示す。
‘ @brief グループ階層を再帰的に走査し、指定条件のシェイプを操作する
‘ @param shpTarget 操作対象のシェイプ(またはグループ)
Public Sub ProcessShapesRecursively(ByVal shpTarget As Visio.Shape)
Dim shpChild As Visio.Shape
‘ ここが核心:グループ内シェイプの存在チェック
‘ Visioではグループ外のシェイプに対してShapesを呼ぶとエラーになるため確認必須
If shpTarget.Type = Visio.VisShapeTypes.visTypeGroup Then
‘ 子シェイプのコレクションを走査
For Each shpChild In shpTarget.Shapes
‘ 再帰呼出:ここで階層を潜る
Call ProcessShapesRecursively(shpChild)
Next shpChild
Else
‘ リーフ(子要素)に到達した際の処理
‘ 例:特定の名称を持つシェイプのテキストを書き換える
If shpChild.Name Like “Target_Component_” Then
shpChild.Text = “Updated_Via_VBA”
End If
End If
‘ メモリ最適化:再帰の帰りがけに参照をクリアする
Set shpChild = Nothing
End Sub
—
3. シニアエンジニアのための最適化Tips
① Shape.Typeによるフィルタリング
全てのシェイプに対して再帰を行うのは無駄だ。`visTypeGroup` 以外のシェイプに対しても `Shapes` コレクションへアクセスしようとすると、Visioは無用なオブジェクト生成を行い、低速化を招く。必ず `If .Type = visTypeGroup` でガードをかけること。
② Windows APIを用いた描画の抑制
大規模な図形を一括処理する場合、画面の再描画(Redraw)が最大のボトルネックとなる。`Application.ScreenUpdating` を `False` にしてもなお重い場合は、Windows APIの `LockWindowUpdate` を併用し、ウィンドウハンドルをロックする手法も検討すべきだ。
‘ API宣言(モジュールヘッダに配置)
Private Declare PtrSafe Function LockWindowUpdate Lib “user32” (ByVal hWndLock As LongPtr) As Long
‘ 実行時の制御
LockWindowUpdate Application.WindowHandle32
‘ … 処理の実行 …
LockWindowUpdate 0 ‘ 解除
③ エラーハンドリングの徹底
グループの編集は、グループ自体が「ロック」されていたり、`Layer` の設定で非表示になっていたりと、予期せぬエラーが頻発する。`On Error Resume Next` で逃げるのではなく、`Shape.Protection` プロパティをチェックし、操作可能な状態か判定するサブルーチンを挟むのが、プロフェッショナルの矜持だ。
—
結論:Visioを「データソース」として扱う視点
Visioを単なるドローイングツールと見なすな。これは空間座標と階層構造を持った、高度なデータベースである。
再帰処理をマスターすることは、Visioの描画構造を論理的に掌握することを意味する。一度この階層構造の走査をアルゴリズムとして確立してしまえば、数百枚の図面を横断する自動化タスクも、もはや朝飯前のルーチンワークに過ぎない。
次にあなたが書くコードが、既存の「動かないコード」を葬り去り、堅牢なシステムの一部となることを期待している。
