Visio VBAを極限まで加速させろ:`DeferRecalc`で数千のシェイプ操作を「一瞬」で終わらせる技術
開発プロジェクトの現場で、こんな絶望感を味わったことはないか?
「数百、数千の機器レイアウトやネットワーク図をVBAで自動生成・更新するツールを作った。しかし、いざ実行ボタンを押すと、画面がガタガタと再描画され、1つのシェイプを動かすたびに数秒が経過し、全体で数十分もフリーズしてしまう……」
もし君が、画面が書き換わるたびにVisioに計算とレンダリングをさせているなら、それは大容量図面における「最大のアンチパターン」を踏んでいる。
Visioは非常にリッチなグラフィックエンジンを持っている。しかし、それがVBAからの大量一括処理においては致命的な足枷になる。シェイプを1つ追加・移動するたびに、接続線のルーティング再計算、数式(ShapeSheet)の依存関係解決、そして画面の再描画が走るからだ。
この不毛なオーバーヘッドを完全に断ち切り、処理速度を劇的に向上させるための切り札が `Application.DeferRecalc` である。
今回は、このプロパティを軸に、大規模な図面自動化をエンタープライズレベルの堅牢性で実現するための極意を伝授しよう。
—
1. なぜVisio VBAは遅いのか?(根本原因の理解)
デフォルトの状態では、VBAからシェイプのプロパティ(`PinX`, `CellsSRC` など)を変更するたびに、Visioのエンジンは以下の処理を同期的に実行する。
1. 数式(Formula)の評価と依存関係の再計算
2. シェイプの位置・サイズの確定
3. コネクタのルーティング(経路探索)の再計算
4. UIおよび描画キャンバスのリフレッシュ(画面更新)
シェイプが10個なら人間には知覚できない。しかし、これが500個、1000個となるとどうか?
1回の操作に0.05秒かかるとすれば、1000個で50秒。さらに処理が複雑化すれば数分単位の時間泥棒となる。
ここで登場するのが `Application.DeferRecalc` だ。
—
2. `DeferRecalc` のメカニズムとライフサイクル
`Application.DeferRecalc` は、Boolean型のプロパティである。
- `Application.DeferRecalc = True`
Visioのバックグラウンド計算および画面の再描画を「一時停止(保留)」する。この間、VBAからの変更はメモリ上でサイレントに処理され、描画や再計算のコストが完全にゼロになる。
- ジグソーパズルのように組み立てる
保留中の間にどれだけシェイプを生成・移動・結合しても、Visioは泣き言を言わずにメモリ上で座標計算だけを溜め込んでいく。
- `Application.DeferRecalc = False`
この瞬間、溜め込まれていたすべての変更に対する依存関係の解決、ルーティング、そして一度だけの「一括描画」が爆発的な速度で実行される。
⚠️ 絶対に守るべき鉄則:エラーハンドリングの義務
`DeferRecalc = True` にしている最中にVBAでランタイムエラーが発生し、プログラムが途中で止まった場合どうなるか?
Visioの再計算機能が停止したまま(ゾンビ状態)になり、図面が一切更新されなくなる、あるいはVisio自体が不安定になる。
したがって、`DeferRecalc` を使う際は、必ず `On Error GoTo` によるトランザクション管理(確実に `False` に戻す仕組み) を実装しなければならない。これがプロとアマを分ける境界線だ。
—
3. 【実務対応】プロダクションコード例
以下に、数百個のシェイプをグリッド状に高速配置し、最後に一括接続する実用的なVBAプロシージャを示す。この設計パターンをそのままテンプレートとして活用してほしい。
Option Explicit
”’
”’
Public Sub HighSpeedGenerateShapes()
‘ 処理開始時刻の記録(パフォーマンス計測用)
Dim startTime As Double
startTime = Timer
‘ 1. 画面更新と自動計算の停止(ここからトランザクション開始)
Dim originalScreenUpdating As Boolean
originalScreenUpdating = Application.ScreenUpdating
‘ 念のため、多重トグルを防ぐため現在の状態を保持しつつオフにする
Application.ScreenUpdating = False
Application.DeferRecalc = True
‘ エラーハンドリングのトリアージエリアへジャンプする準備
On Error GoTo ErrorHandler
‘ — 【コア処理エリア】 —
Dim vsoPage As Visio.Page
Set vsoPage = ActivePage
Dim vsoMaster As Visio.Master
‘ 例として「長方形」のマスターシェイプを取得(ドキュメントのステンシル等から)
Set vsoMaster = Visio.Documents.Item(“BASIC_U.VSSX”).Masters.ItemBstr(“Rectangle”)
Dim i As Long, j As Long
Dim targetShape As Visio.Shape
Dim xPos As Double, yPos As Double
Const ROW_COUNT As Long = 20
Const COL_COUNT As Long = 25
Const SPACING_X As Double = 1.2
Const SPACING_Y As Double = 1.0
‘ 500個(20×25)のシェイプを爆速で配置
For i = 1 To ROW_COUNT
For j = 1 To COL_COUNT
xPos = 1.0 + (j SPACING_X)
yPos = 10.0 – (i SPACING_Y)
‘ シェイプのドロップ(DeferRecalcのおかげでこのループは一瞬で終わる)
Set targetShape = vsoPage.Drop(vsoMaster, xPos, yPos)
‘ テキストの付与
targetShape.Text = “Node_” & i & “_” & j
‘ カスタムプロパティ(ShapeData)の書き込みなどもここで一括処理
‘ Call SetShapeData(targetShape, “ID”, i 100 + j)
Next j
: Next i
‘ ———————–
ErrorHandler:
‘ 2. 【最重要】エラーの有無に関わらず必ず再計算・描画を復元する
Application.DeferRecalc = False
Application.ScreenUpdating = originalScreenUpdating
‘ 画面を強制的にリフレッシュ
ActiveWindow.Redraw
‘ エラーハンドリング
If Err.Number <> 0 Then
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “処理中断”
Else
Dim elapsedTime As Double
elapsedTime = Timer – startTime
MsgBox “処理が完了しました。” & vbCrLf & _
“生成数: ” & (ROW_COUNT COL_COUNT) & ” シェイプ” & vbCrLf & _
“実行時間: ” & Format(elapsedTime, “0.00”) & ” 秒”, vbInformation, “高速化完了”
End If
End Sub
—
4. チーフアーキテクトからの実践アドバイス:さらなる高みへ
この `DeferRecalc` 技法だけでも処理速度は 5倍〜20倍 に跳ね上がるが、エンタープライズレベルのツールに仕上げるためには、以下の合わせ技が有効だ。
1. `Application.ScreenUpdating = False` との併用
`DeferRecalc` は「計算」を止めるが、UIの「描画」は完全に抑えきれない場合がある。そのため、上記のコード例のように `ScreenUpdating = False` とセットで用いるのが鉄則である。
2. イベントの無効化 (`EventEnabled`)
もし図面に `ShapeAdded` などのイベントハンドラ(Classモジュール)が紐付いている場合、大量生成時にそれがバーストして動作が重くなる。一括処理の際は `Application.EventEnabled = False` も併用を検討せよ。
3. データベースやExcel連携時の注意点
外部のSQL ServerやExcelから数千件のデータを取得しながらシェイプを生成する場合、「データ取得(メモリ上)」⇒「DeferRecalc = True」⇒「シェイプ一括生成」⇒「DeferRecalc = False」 の順序を守れ。I/O処理の最中に `DeferRecalc` を挟むと、かえってコードの可読性が下がりバグの温床になる。
—
総括
VBAにおけるパフォーマンスチューニングとは、「無駄なコストを Visio に払わせないこと」に尽きる。
これまで「VisioのVBAは遅いから仕方ない」と諦めていたエンジニア諸君。今日からその言い訳は通用しない。`DeferRecalc` を正しく設計に組み込み、圧倒的なスピードと安定性を誇るプロフェッショナルな自動化ツールを構築してほしい。
