Visio VBAの限界を突破せよ:DropManyによる「100倍速」配置エンジニアリング
Visioの自動化において、多くの開発者が陥る「最初の死の罠」がある。それが「ループ内での`Page.Drop`メソッドの多用」だ。
数個のシェイプを置く程度なら問題はない。だが、数百、数千のノードを持つネットワーク図や組織図を生成する際、`For Each`ループの中で一つずつ`Drop`を呼び出していれば、CPUはVisioの描画更新と再計算のオーバーヘッドで悲鳴を上げ、実行時間は指数関数的に増大する。
今日、君たちが学ぶのは、Visioのパフォーマンスを支配する「一括処理の極意」だ。
—
1. なぜ「Drop」は遅いのか?
`Page.Drop`を実行するたび、Visioは以下の処理を強制的に行う。
1. 図形の挿入と計算: 形状のジオメトリ計算、コネクタの再ルーティング。
2. イベントの発火: `ShapeAdded`などのイベントがその都度発生する。
3. UIの再描画: 画面の更新が走り、描画パイプラインを占有する。
これを1,000回繰り返せば、たとえ1回0.1秒の処理でも100秒かかる。ユーザーが「フリーズした」と勘違いし、タスクマネージャーを起動させるには十分な時間だ。
解決策は明確だ。描画エンジンを一度だけ叩き、メモリ上で配列を流し込むこと。それが `Page.DropMany` である。
—
2. 実装の設計思想:DropManyの極限効率
`DropMany`を使いこなすには、以下の3つの配列を準備する必要がある。
- Masters: 配置するマスターシェイプの参照配列。
- XY: 配置先の座標配列。
- Result: 生成されたシェイプが格納される出力用配列(参照渡し)。
プロダクションコード:高速配置の雛形
このコードは、実務でそのまま利用できる堅牢なテンプレートだ。
‘ @description: 大量のシェイプを高速配置するためのエンジン
Public Sub BatchDropShapes(ByVal targetPage As Visio.Page, _
ByVal masterObj As Visio.Master, _
ByVal xyCoords() As Double)
Dim count As Long
count = UBound(xyCoords) / 2 + 1 ‘ XとYのペア数
‘ 結果を受け取るための配列を用意(DropManyはここに作成されたオブジェクトを返す)
Dim outShapes() As Object
‘ 描画の抑制(パフォーマンスの定石)
Application.ScreenUpdating = False
On Error GoTo Cleanup
‘ DropManyの実行
‘ 第1引数: マスターの配列(今回は単一マスターの繰り返し)
‘ 第2引数: 配置座標の配列
‘ 第3引数: 出力用配列
Dim masters(0 To 0) As Object
Set masters(0) = masterObj
‘ 座標に合わせてマスター配列を拡張する必要がある場合はここで調整
Dim masterArray() As Object
ReDim masterArray(0 To count – 1)
Dim i As Long
For i = 0 To count – 1
Set masterArray(i) = masterObj
Next i
targetPage.DropMany masterArray, xyCoords, outShapes
Cleanup:
Application.ScreenUpdating = True
If Err.Number <> 0 Then MsgBox “エラー発生: ” & Err.Description
End Sub
—
3. 実務で勝つための「設計上の注意点」
座標の正規化とメモリ管理
`XY`配列は `Double型` で、`{X1, Y1, X2, Y2, …}` の順に並べる必要がある。データベースからデータを取得する場合、`Recordset`を直接回さず、一度配列にロードしてから `DropMany` に渡すこと。ディスクI/Oとメモリのアクセスコストを分離するのが、アーキテクトの視点だ。
イベント抑制の徹底
`DropMany` を使う際、`Application.EventsEnabled = False` を併用することを検討せよ。大量のシェイプを配置する際、個別のシェイプに紐付いた `ShapeAdded` イベントが暴走すると、配置完了後に遅延が発生する可能性がある。
データベース連携の最適化
外部データ(CSVやSQL Server)からシェイプを生成する場合、以下のフローを遵守せよ。
1. データ取得: SQLで一括取得し、配列に格納。
2. 事前計算: 座標計算をVBA内で行い、`XY`配列を構築。
3. 一括配置: `DropMany` で一気に叩き込む。
4. 後処理: 属性データ(DataRecordsetへのリンクやShapeDataの更新)の付与。
—
最後に:エンジニアとしての矜持
「動けばいい」コードは、誰でも書ける。だが、1,000個のオブジェクトを扱った瞬間に崩壊するコードは、プロの成果物ではない。
`DropMany` を使うことは、単なる高速化以上の意味を持つ。それは、「Visioという複雑なオブジェクトモデルの内部構造を理解している」という証明だ。
次回の開発では、ループの中にある `Drop` を見つけ次第、迷わずこのロジックに書き換えてほしい。コードが軽快に動く様を見たとき、君はまた一つ、真の自動化エンジニアへと近づいているはずだ。
何か詰まったら、いつでも戻ってくるといい。理論と実装の境界線で、君を待っている。
