Visio VBAの深淵:Selectionオブジェクトを起点とする「非破壊的」一括処理アーキテクチャ
Visioの自動化において、初心者が陥る罠は「`ActivePage.Shapes`をループで回す」という愚行だ。全走査は計算量を増大させ、不要なオブジェクトへのアクセスでメモリを浪費する。真のエンジニアは、ユーザーの「選択」というコンテキストを起点にし、対象を必要最小限に絞り込む。
本稿では、`Selection`オブジェクトを軸とした、堅牢かつ高パフォーマンスな一括処理の実装論を説く。
—
1. Selectionオブジェクトの本質と「非同期」の罠
`ActiveWindow.Selection`は、単なる図形の集合ではない。それは、ユーザーの意図(Intent)そのものだ。ここを操作の起点にすることで、システムは「全対象」から「限定対象」へと計算コストを劇的に落とすことができる。
しかし、注意が必要だ。`Selection`は動的に変化する。ループ処理中に図形を削除したり、コネクタをリダイレクトしたりすると、内部ポインタが破損するリスクがある。
シニアのためのベストプラクティス
1. Selectionの確定: ループに入る前に、現在の選択範囲を確定させ、イテレータを分離する。
2. 型安全性の確保: `Shape.Type`をチェックし、グループやコネクタといった例外を事前に弾く。
3. イベントの抑止: `Application.ScreenUpdating = False` は必須だが、さらに`Application.DeferRecalc = True`を組み合わせ、再計算を後回しにするのが鉄則だ。
—
2. 実装:Selectionを走査する堅牢なアーキテクチャ
以下に、大規模図面でも音を上げない、メモリ管理を意識した標準テンプレートを提示する。
Option Explicit
”’
”’
Public Sub ProcessSelectedShapes()
Dim sel As Visio.Selection
Dim shp As Visio.Shape
Dim i As Long
‘ 1. コンテキスト取得
Set sel = Visio.ActiveWindow.Selection
‘ 2. 最適化:描画と再計算を停止
Application.ScreenUpdating = False
Application.DeferRecalc = True
On Error GoTo Cleanup
‘ 3. Selectionを確定後のループ処理
‘ カウントダウンで回すことで、図形の削除・追加によるインデックスズレを回避
For i = sel.Count To 1 Step -1
Set shp = sel.Item(i)
‘ 4. 型チェック:コネクタやグループを除外する防御的プログラミング
If shp.OneD = False Then
‘ ここにロジックを記述
Call ApplyEnterpriseStyle(shp)
End If
‘ オブジェクト解放(VBAのGCを待たない姿勢)
Set shp = Nothing
Next i
Cleanup:
‘ 5. 後処理:リソースを確実に解放し、描画を復帰
Application.DeferRecalc = False
Application.ScreenUpdating = True
If Err.Number <> 0 Then
MsgBox “エラー発生: ” & Err.Description, vbCritical
End If
Set sel = Nothing
End Sub
Private Sub ApplyEnterpriseStyle(ByRef shp As Visio.Shape)
‘ 業務データ付与の例:ShapeSheetへの直接書き込みよりも高速なCell操作
With shp
.Cells(“LineWeight”).FormulaU = “2pt”
.Cells(“FillForegnd”).FormulaU = “RGB(240,240,240)”
‘ カスタムプロパティへの書き込み
If .CellExists(“Prop.ProcessID”, False) Then
.Cells(“Prop.ProcessID”).FormulaU = Chr(34) & “PRC-” & Format(Now, “HHNNSS”) & Chr(34)
End If
End With
End Sub
—
3. レガシー環境とWindows APIの活用
大規模なVisioアドイン開発において、時折遭遇するのが「描画のスタック」や「巨大なプロセスのハングアップ」だ。これを回避するため、Windows APIによる監視や、UIスレッドの開放を行うケースがある。
例えば、長時間処理中に「Visioがフリーズしている」と誤認されないよう、`DoEvents`を適切に配置する。ただし、過剰な`DoEvents`は再帰呼び出しのリスクを孕む。
アーキテクトの視点:
- メモリ解放: `Set shp = Nothing` はVBAでは気休めのように思われがちだが、大規模なループ内では明確なスコープ管理として機能する。
- レガシー連携: APIを使用してExcelのデータソースと同期させる場合、`Late Binding`(CreateObject)ではなく、参照設定による`Early Binding`を選択し、コンパイル時チェックを最大化せよ。
—
4. 結び:エンジニアの誇り
VisioのVBAは、単なる事務自動化ツールではない。図面という非構造データを、メタデータを持つ構造化データへと昇華させるための強力な武器である。
「なんとなく動くコード」ではなく、「選択範囲というユーザーの意図を正確に読み取り、メモリと計算資源を最適に配分するコード」を書くこと。それこそが、伝説的なエンジニアと、その他大勢のプログラマーを隔てる境界線だ。
明日からの現場で、あなたのコードが Visio の挙動を一段上の次元へ引き上げることを期待している。
