Visio VBAの深淵:数千のセルを一瞬で支配する「一括演算」の極意
VisioのVBAを書いているとき、あなたは「.CellsU(“Width”).Formula = …」をループの中に書いていないだろうか? もしそうなら、あなたのプログラムはVisioの描画エンジンを単なる事務員のようにこき使い、無駄なオーバーヘッドでCPUを枯渇させている。
数千のシェイプを扱う大規模図面において、1セルずつの逐次アクセスは「死」を意味する。Visioのオブジェクトモデルを真に制御したいのであれば、個々のセルへの執着を捨て、「配列(Array)」という名のメモリ領域で一括処理するというパラダイムシフトが必要だ。
本稿では、伝説的なパフォーマンスを叩き出す `GetFormulasU` と `SetFormulasU` の真髄を伝授する。
—
1. なぜ逐次処理は「罪」なのか
Visioの `Cell` オブジェクトへのアクセスは、COMインターフェースを介したコストの高いプロセスだ。ループ内で `CellsU` を呼び出すたびに、Visioはシェイプの数式を再評価し、依存関係の依存関係をチェックし、GUIへ再描画のシグナルを送る。
- 逐次アクセスのコスト: 1回の呼び出しにつき、数ミリ秒のレイテンシが積み重なる。
- イベントの暴走: 処理のたびに発生する `CellChanged` イベントが、システム全体を泥沼の重さに引きずり込む。
これらを解消し、メモリ空間で完結させるのが `GetFormulasU` / `SetFormulasU` だ。
—
2. 鋼鉄のコード:配列による一括操作の実装
以下のコードは、選択したシェイプ群の「Width」と「Height」を一度に取得し、倍率を掛けて一括で書き戻すプロトタイプだ。
Option Explicit
‘ 大規模データ操作のための高速化ルーチン
Public Sub OptimizeShapeDimensions()
Dim shps As Visio.Selection
Dim count As Long
Dim i As Long
‘ 1. オブジェクトの明示的取得
Set shps = ActiveWindow.Selection
count = shps.Count
If count = 0 Then Exit Sub
‘ 2. メモリ上に数式用配列を確保
‘ GetFormulasUは引数として「セルの名前(パス)」の配列を要求する
Dim cellNames(0 To 1) As String
cellNames(0) = “Width”
cellNames(1) = “Height”
‘ 結果を格納する2次元配列 (Row:シェイプ数, Col:セル数)
Dim formulas() As Variant
‘ 3. 一括読み出し(イベントを無視し、メモリから直接吸い出す)
shps.GetFormulasU cellNames, formulas
‘ 4. 配列上で計算(ここが真骨頂:Visioに触れずに演算する)
For i = 0 To count – 1
‘ 数式(Formula)を解析して計算するロジックをここに
‘ 注: 複雑な数式の場合は、Eval関数や正規表現でのパースが必要になる
formulas(i, 0) = “Width1.2” ‘ 幅を20%拡張
formulas(i, 1) = “Height1.2” ‘ 高さを20%拡張
Next i
‘ 5. 一括書き込み(Visioへの反映を最小のトランザクションで行う)
‘ Application.DeferRecalc を活用すれば、再計算を一時停止可能
Application.DeferRecalc = True
On Error GoTo Cleanup
shps.SetFormulasU cellNames, formulas
Cleanup:
Application.DeferRecalc = False
‘ 6. メモリ解放の徹底(VBAにおけるリーク防止の鉄則)
Set shps = Nothing
End Sub
—
3. シニアエンジニアが押さえるべき「極限の知見」
A. DeferRecalc の賢明な利用
`Application.DeferRecalc = True` は、Visioの再計算エンジンを停止させる魔法のスイッチだ。大量の `SetFormulasU` を実行する直前にこれを設定し、処理完了後に `False` に戻す。これにより、数千回の再描画を1回のコミットへと昇華させることができる。
B. GetFormulasU と GetResultsU の使い分け
- GetFormulasU: 数式(例: `”Width2″`)を操作したい場合。数式の依存関係を保持したまま書き換えたいならこちら。
- GetResultsU: 評価済みの値(例: `”10 mm”`)を操作したい場合。単位変換や動的な値の代入にはこちらの方が圧倒的に高速かつ安全だ。
C. オブジェクトのライフサイクル管理
VBAはCOMベースの言語だ。`Set shps = Nothing` を怠ることは、大規模図面でのメモリリークへの招待状に等しい。特に、ループ内でシェイプを動的に生成するような設計では、必ず親オブジェクトへの参照を明示的に解放せよ。
D. レガシーシステム連携への適用
外部データベースから取り込んだデータをVisioに流し込む際、1つずつセルを更新して画面が「砂時計」になるのを待たせてはならない。
1. 全データを配列にロードする。
2. `SetFormulasU` で一気に叩き込む。
3. 画面を一度だけ `Application.ActiveWindow.DeselectAll` してリフレッシュさせる。
この手順こそが、プロフェッショナルが守るべきUI/UXの作法である。
—
結びに代えて
Visio VBAは、古臭い言語かもしれない。しかし、その根底にあるCOMモデルとシェイプの依存関係エンジンを理解すれば、これほどまでに強力な自動化プラットフォームは他にない。
「動けばいい」というコードから卒業せよ。メモリ配置を意識し、描画エンジンの挙動を制御し、ボトルネックを排除する。その先にこそ、真の業務自動化エンジニアの領域が広がっている。
さあ、あなたの図面を、一瞬で書き換えてみせろ。
