【入門編】Application.DeferRecalcによる描画・計算保留:大容量図面でのVBA処理速度を劇的に向上させる方法 – Visio VBA解析バイブル

スポンサーリンク

こんにちは!Visioでの自動化に挑むあなたへ。
マクロの記録を卒業し、「よし、自分でコードを書くぞ!」と意気込んで数百個ものシェイプをゴリゴリ動かすプログラムを作ってみたものの……。

「……あれ? 画面がフリーズしたみたいに固まって、終わるまでコーヒーを何杯飲めばいいんだ?」

そんな絶望的な待ち時間に直面したことはありませんか?
もし心当たりがあるなら、あなたは今、Visio VBAの「最大の罠と、それを打ち破る最強の呪文」を学ぶべき最高のタイミングにいます。

今日は、数千個のシェイプを扱う大容量図面であっても、一瞬で処理を終わらせるための極意`Application.DeferRecalc`(デファー・リカルク)について、お姉さんのように優しく、かつエンジニアの魂を込めて徹底解説していきますね。ここをクリアすれば、あなたのVisio VBAスキルは一気にプロの領域へ到達しますよ!

1. なぜVisioのVBAは遅いのか?(オブジェクトモデルの残酷な真実)

私たちがVBAで次のようなコードを書いたとします。

Dim i As Long
For i = 1 to 500
ActivePage.DrawRectangle i 10, i 10, i 10 + 20, i 10 + 20
Next i

人間から見れば「500個の四角形を並べて描くだけ」のシンプルな処理です。しかし、Visioの心臓部(エンジン)の動きを覗いてみると、背後でこんな悲劇が起きています。

1. 1個目の四角形を描く
2. 「大変だ!図面全体のレイアウトが変わったかもしれない!数式を再計算しなきゃ!」 → 全シェイプの位置・接続・数式を再計算
3. 「画面を更新しなきゃ!」 → 画面の描画をリフレッシュ
4. 2個目の四角形を描く
5. 「また再計算だ!」 → 全シェイプの再計算(2回目)
6. (以下、500回繰り返し……)

そう、Visioは「シェイプを1つ配置・変更するたびに、図面全体の再計算と画面描画を律儀に行う」というお節介な性質を持っています。これが、大量のシェイプを扱うマクロが異次元の遅さになる根本原因です。

2. 救世主 `Application.DeferRecalc` とは何か?

このお節介をピタッと止めさせる魔法のプロパティが、`Application.DeferRecalc` です。

日本語に訳すなら「再計算の延期」。
処理の開始前に `DeferRecalc = True` を宣言すると、Visioはこう思います。

> 「承知いたしました! では、今からあなたが何をしようと、再計算も画面描画も一切行わず、ただ言われた通りに裏でシェイプをいじり続けますね。終わったら教えてください!」

そして、処理の最後に `DeferRecalc = False` に戻した瞬間、Visioは溜め込んだすべての変更に対する再計算を「1回だけ」まとめて実行します。

この仕組みにより、500回の再計算と画面描画が発生していた処理が、わずか「1回」に凝縮されるため、実行速度が劇的に向上するというわけです。

3. 実践!爆速化コードのテンプレート

それでは、実際に `DeferRecalc` を組み込んだ、安全かつ美しいVBAコードの書き方を見ていきましょう。現場でそのままコピペして使えるテンプレートです。

Sub FastDrawingSample()
Dim startTime As Double
startTime = Timer ‘ 処理時間計測用

‘ 【重要】エラー発生時にも確実に再計算をONに戻すための布石
On Error GoTo ErrorHandler

‘ 1. 再計算と画面更新を一時停止(ここが今日の主役!)
Application.DeferRecalc = True
Application.ScreenUpdating = False ‘ 画面描画も止めるとさらに爆速に!

‘ — ここから重い処理 —
Dim i As Long
Dim shp As Shape

‘ 例として、500個のシェイプをグリッド状に配置する
For i = 1 To 500
Set shp = ActivePage.DrawRectangle(2, -2, 3, -3)
‘ 位置を少しずつずらす(この時点では再計算されないため高速)
shp.Cells(“PinX”).ResultIU = (i Mod 20) 1.5 + 1
shp.Cells(“PinY”).ResultIU = -1 (i \ 20) 1.5 – 1
Next i
‘ — 重い処理ここまで —

ErrorHandler:
‘ 2. 処理が終わったら(またはエラーが起きても)必ず元に戻す!
Application.DeferRecalc = False
Application.ScreenUpdating = True

‘ 異常終了時のエラー処理
If Err.Number <> 0 Then
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Else
MsgBox “処理が完了しました! 実行時間: ” & Format(Timer – startTime, “0.00”) & “秒”, vbInformation
End If

End Sub

💡 コードの最重要ポイント(ここテストに出ます!)

1. `Application.ScreenUpdating = False` とのコンボ技
`DeferRecalc` と合わせて画面描画自体も止めることで、パフォーマンスの限界を突破できます。
2. エラー対策の `On Error GoTo`
もし `DeferRecalc = True` の状態でコードがエラー落ちすると、Visioの再計算機能が停止したままの状態(ゾンビ状態)になり、最悪の場合Visioがまともに動かなくなります。必ず `ErrorHandler` を用意し、どんな状況でも確実に `False` に戻す仕組みをセットで作るのが、プロのエンジニアの流儀です。

4. 陥りやすい罠:DeferRecalc中やってはいけないこと

万能に見える `DeferRecalc` ですが、1つだけ巨大な注意点があります。

それは、「再計算が停止している最中に、計算結果に依存する値を取得しようとしてはいけない」ということです。

例えば、以下のようなコードはバグの原因になります。

Application.DeferRecalc = True

‘ シェイプAを動かす
shpA.Cells(“PinX”).ResultIU = 5.0

‘ 【危険】今動かしたばかりのシェイプAの位置から、別のシェイプBの位置を計算しようとする
Dim currentX As Double
currentX = shpA.Cells(“PinX”).ResultIU ‘ ← まだ再計算されていないため、古い値が取れるかエラーになる!

Application.DeferRecalc = False

`DeferRecalc = True` の間、Visioの頭の中は「現実逃避モード」です。シェイプを動かしても座標の連動や数式の評価は行われていません。「計算結果を使った次の処理」を行いたい場合は、一度 `DeferRecalc = False` にして頭をスッキリさせてから行うか、VBA側で純粋な数学的計算(変数を使った計算)で座標を導き出すようにしてください。

まとめ

いかがでしたか?今回は Visio VBA における高速化の極意 `Application.DeferRecalc` について解説しました。

  • 数百個以上のシェイプを操作する時は、必ず `DeferRecalc = True` を使う
  • 画面描画を止める `ScreenUpdating = False` も一緒に使えばさらに効果的
  • エラーが起きても必ず `False` に戻せるように、エラーハンドリングを必ず書く
  • 停止中は「計算結果に依存する値の取得」に気を付ける

この4つをマスターすれば、もう重い図面を相手にイライラすることはなくなります。あなたの作るマクロが一瞬で仕事を終わらせてくれる姿を想像してみてください。なんだかワクワクしてきませんか?

ここをクリアしたあなたなら、もうVisio VBAの基礎はバッチリです。自信を持って、次の自動化の扉を開けていきましょう!

タイトルとURLをコピーしました