【Visio VBA】1,000個の図形を瞬殺せよ:DropManyによる「超高速一括配置」の極意
Visioの自動化において、初心者が必ず陥る罠がある。それは、`Page.Drop`をループ内で呼び出し続ける「地獄の反復処理」だ。
「100個程度の図形なら問題ない」と高を括っているうちに、データ量が数千件を超えた瞬間、描画エンジンは悲鳴を上げ、PCはフリーズする。なぜなら、`Drop`メソッドを呼ぶたびに、Visioは描画の再計算、イベントのトリガー、Undoスタックへの書き込みを律儀に繰り返すからだ。
真の自動化エンジニアなら、「描画は一度のトランザクションで完結させる」という鉄則を忘れてはならない。今回は、Visioの描画ボトルネックを物理的に破壊する`Page.DropMany`の極意を伝授する。
—
1. なぜ「Drop」を連打してはいけないのか
`Page.Drop`は個別の図形を配置するには便利だが、以下のコストをその都度支払っている。
1. 描画再計算: 配置のたびに画面の再描画が行われる。
2. イベント発行: `ShapeAdded`などのイベントがその都度発生し、リスナーが登録されていれば処理が重なる。
3. Undo管理: 1回ずつUndoスタックに記録されるため、メモリを激しく消費する。
これらを解決するのが、配列を渡して一括配置する`Page.DropMany`だ。これは言わば「バルクインサート」であり、描画エンジンに対して「これらを一度に描け」と指示する、極めて低レイヤーに近いアプローチである。
—
2. 実践:DropManyによる爆速配置コード
このコードは、実務で頻出する「マスター図形を特定の座標リストに一括配置する」パターンを想定している。
‘ ———————————————————
‘ 目的: 配列データを用いて図形を高速に一括配置する
‘ ———————————————————
Public Sub BulkDropShapes()
Dim vsoPage As Visio.Page
Dim vsoMaster As Visio.Master
Dim vsoShapes() As Visio.Shape
Dim xyArray(0 To 1) As Double
Dim posArray() As Double
Dim i As Long
Dim count As Long: count = 100 ‘ 配置したい図形の数
Set vsoPage = ActivePage
Set vsoMaster = Application.Documents(“StencilName.vssx”).Masters(“ShapeName”)
‘ 配置座標用配列の準備 (x1, y1, x2, y2, …)
ReDim posArray(0 To (count 2) – 1)
‘ 座標計算(ここをDBやCSVからの読み込みに差し替える)
For i = 0 To count – 1
posArray(i 2) = i 0.5 ‘ X座標
posArray(i 2 + 1) = i 0.5 ‘ Y座標
Next i
‘ 重要: 描画更新を一時停止して高速化を最大化
Application.ScreenUpdating = False
‘ DropManyを実行
‘ 第1引数: 配置するマスター図形の配列 (今回は単一種類を複数)
‘ 第2引数: 座標ペアの配列
‘ 第3引数: 返り値として配置されたShapeオブジェクトが入る
vsoPage.DropManyArray vsoMaster, posArray, vsoShapes
‘ 後処理
Application.ScreenUpdating = True
Debug.Print “配置完了: ” & UBound(vsoShapes) + 1 & ” 個の図形を配置しました。”
End Sub
—
3. 堅牢な設計のための「3つの鉄則」
現場で動くコードにするためには、技術的なコツだけでなく、「異常系への備え」が不可欠だ。
① 描画更新の抑制 (`ScreenUpdating`)
`Application.ScreenUpdating = False` は必須だ。これを行わないと、`DropMany`を使っていても、内部的に描画リクエストが走る可能性がある。最後に必ず `True` に戻すよう、エラーハンドラで確実に制御すること。
② 座標データのバリデーション
`DropMany`に渡す `posArray` は「Double型の一次元配列」でなければならない。DBから取得したデータをそのまま突っ込むのではなく、必ず型変換と要素数の整合性を確認するバリデーションを挟むこと。ここを怠ると、Visioは容赦なくクラッシュする。
③ Undoスコープの活用
`Application.BeginUndoScope` と `EndUndoScope` を使用し、一括配置全体を一つの「Undo単位」にまとめること。これにより、誤った配置を一瞬でロールバックできるようになり、ユーザーの信頼を獲得できる。
—
4. プロの視点:ファイル・DB連携の注意点
大規模な配置処理を行う際、データソース(ExcelやSQL Serverなど)からの読み込みがボトルネックになることが多い。
- メモリ上のバッファリング: ループ内で毎回DBクエリを投げるのは愚の骨頂だ。最初に全データを配列にロード(配列への一括読み込み)し、VBAのメモリ上で座標計算を完結させてから `DropMany` に渡す。これが「プロのエンジニア」が書くコードの標準だ。
- マスター図形のキャッシュ: `vsoMaster` の取得はループの外で行い、オブジェクト参照を使い回す。これだけで数ミリ秒の差が出る。
最後に
`DropMany` は、単なるメソッドではない。それは「Visioの内部処理を理解しているか」というエンジニアの試金石だ。
もし、今あなたが書いているコードが `for` ループの中で `Drop` を呼び出しているなら、それは今すぐ書き換えるべき技術的負債である。この記事の知見を武器に、誰よりも速いVisioソリューションを構築してほしい。
検討を祈る。
