【入門編】【中級】Application.DeferRecalcによる描画保留:大規模図面のVBA処理時間を劇的に短縮する – Visio VBA解析バイブル

スポンサーリンク

皆さん、こんにちは! 最先端の業務自動化の世界へようこそ。
私はVisio VBAの奥深さを知り尽くしたチーフアーキテクトとして、皆さんが抱える「Visio図面が重い」「VBAマクロが遅い」「フリーズする」といった悩みに、根本から切り込む知識をお届けします。

今回は、数千、数万個の図形を扱う大規模なVisio図面をVBAで操作する際に、その処理時間を劇的に短縮し、まるで魔法のようにスムーズな操作を実現する秘策をご紹介します。

大規模Visio図面をVBAで操作する、その「重さ」の正体

Visio図面をVBAで操作する際、「なんでこんなに時間がかかるんだろう?」「VBAを実行するとVisioがフリーズしたようになる」と感じたことはありませんか?
特に、たくさんの図形をコピーしたり、移動させたり、色を変えたりするような処理では、その遅さが顕著になります。

この「重さ」の正体、それはVisioが裏側で絶えず行っている「再計算」と「再描画」にあります。

Visioは「賢すぎる」がゆえに遅くなる?

Visioは非常に賢いアプリケーションです。図形の位置を少し動かすだけでも、以下のようなことを瞬時に判断し、実行しようとします。

1. 図形自体のプロパティ変更: `Shape.Cells(“PinX”).FormulaU = “…”` などで位置が変わる。
2. 関連する図形の再計算: その図形に接続されていたコネクタの経路はどうなる? グループ内の図形は?
3. ページの再描画: 変更された部分だけでなく、関連する全ての描画要素を更新。
4. ウィンドウの更新: 複数のウィンドウが開いていれば、それら全てを更新。

たった一つの図形を操作するだけでも、Visioは「よし、何かが変わったぞ! 全ての関連する情報を最新の状態に保つために、計算し直して、画面を更新しよう!」と、せっせと働き始めるわけです。

これが一つや二つなら問題ありません。しかし、これが数百、数千個の図形に対して行われるとなるとどうでしょう?
図形を1000個移動させるVBAコードがあったとして、Visioは1000回「計算・描画」を繰り返すことになります。これでは、処理が遅くなるのも、フリーズしたようになるのも当然ですよね。

まるで、1000枚の絵を一枚一枚描いては消し、描いては消しを繰り返しているようなものです。非効率極まりない。

Application.DeferRecalcによる描画保留:Visioに「ちょっと待って!」と伝える魔法

ここで登場するのが、今回の主役である`Application.DeferRecalc`プロパティです。
これは、Visioアプリケーションに対して「ちょっと待って! 今は再計算も再描画も一時的にストップして。後でまとめてやるから!」と指示する、まさに魔法のようなプロパティです。

DeferRecalcの役割を理解する

  • `Application.DeferRecalc = True`:
  • Visioが自動で行う再計算(Recalculation)と再描画(Redraw)を一時的に停止します。
  • VBAコードで図形をいくら操作しても、画面は更新されず、内部的な計算も保留されます。まるでVisioが一時的に「眠っている」ような状態です。
  • これにより、VBAコードはVisioの内部処理に邪魔されることなく、高速に図形操作を進めることができます。
  • `Application.DeferRecalc = False`:
  • 停止していた再計算と再描画を再開します。
  • `True`に設定してから行われた全ての変更が、この瞬間に一括で計算され、画面に反映されます。
  • まるで、眠っていたVisioが目を覚まし、「よし、これまでの変更を全部まとめて反映するぞ!」と一気に処理するようなイメージです。

この`DeferRecalc`を適切に使うことで、1000回の「計算・描画」を、たった1回の「計算・描画」に集約できるのです。これにより、VBAの処理時間は劇的に短縮され、大規模図面操作も快適になります。

【実践】Application.DeferRecalcを使いこなすコード例

それでは、実際に`Application.DeferRecalc`を使って、VBAの処理速度を改善するコードを見ていきましょう。
ここでは、アクティブなページに多数の四角形を作成し、それぞれを少しずつずらして配置する処理を例にとります。

準備:テスト用のVisio図面

新しい空白のVisio図面を開いてください。この図面で以下のコードを試します。

コード例1:DeferRecalcを使わない場合(遅い!)

まず、`DeferRecalc`を使わない場合のコードです。どれだけ時間がかかるか、体感してみてください。

Sub CreateShapesWithoutDeferRecalc()
‘ Visioアプリケーションオブジェクトを取得
Dim vsoApp As Visio.Application
Set vsoApp = Visio.Application

‘ 現在アクティブなページを取得
Dim vsoPage As Visio.Page
Set vsoPage = vsoApp.ActivePage

‘ マスタシェイプ(四角形)を取得
‘ 一般的なVisioインストールでは”Basic Shapes”ステンシルに”Rectangle”があります
Dim vsoMaster As Visio.Master
On Error Resume Next ‘ エラーが発生しても処理を継続
Set vsoMaster = vsoApp.Documents.OpenEx(“Basic Shapes.vss”, visOpenRO).Masters(“Rectangle”)
If vsoMaster Is Nothing Then
MsgBox “Basic Shapesステンシル、またはRectangleマスターが見つかりません。”, vbCritical
Exit Sub
End If
On Error GoTo 0 ‘ エラーハンドリングを元に戻す

Dim i As Long
Dim xPos As Double
Dim yPos As Double
Dim startTime As Double
Dim endTime As Double

‘ 処理開始時刻を記録
startTime = Timer

‘ 1000個の四角形を作成し、配置
For i = 1 To 1000 ‘ ここで作成する図形の数を調整できます
xPos = (i Mod 40) 0.5 + 1 ‘ X座標を調整
yPos = Int(i / 40) 0.5 + 1 ‘ Y座標を調整

‘ 図形を作成し、ページに配置
‘ ここでVisioは毎回再計算・再描画を試みます
vsoPage.Drop vsoMaster, xPos, yPos
Next i

‘ 処理終了時刻を記録
endTime = Timer

MsgBox “DeferRecalcを使わない場合: ” & Format(endTime – startTime, “0.00”) & “秒”, vbInformation

‘ オブジェクトを解放
Set vsoMaster = Nothing
Set vsoPage = Nothing
Set vsoApp = Nothing
End Sub

このコードを実行すると、図形が一つずつ描画されるたびに画面がちらついたり、処理が途中で止まっているように見えたりするはずです。1000個の図形だと、かなりの時間がかかるでしょう。

コード例2:DeferRecalcを使う場合(速い!)

次に、`Application.DeferRecalc`を導入したコードです。その速度差に驚くはずです!

Sub CreateShapesWithDeferRecalc()
‘ Visioアプリケーションオブジェクトを取得
Dim vsoApp As Visio.Application
Set vsoApp = Visio.Application

‘ 現在アクティブなページを取得
Dim vsoPage As Visio.Page
Set vsoPage = vsoApp.ActivePage

‘ マスタシェイプ(四角形)を取得
Dim vsoMaster As Visio.Master
On Error Resume Next
Set vsoMaster = vsoApp.Documents.OpenEx(“Basic Shapes.vss”, visOpenRO).Masters(“Rectangle”)
If vsoMaster Is Nothing Then
MsgBox “Basic Shapesステンシル、またはRectangleマスターが見つかりません。”, vbCritical
Exit Sub
End If
On Error GoTo 0

Dim i As Long
Dim xPos As Double
Dim yPos As Double
Dim startTime As Double
Dim endTime As Double

‘ ここからが肝心!エラーハンドリングをしっかり行いましょう
On Error GoTo ErrorHandler

‘ 処理開始時刻を記録
startTime = Timer

‘ ★★★ Visioの再計算・再描画を一時停止 ★★★
vsoApp.DeferRecalc = True
‘ 画面の更新も停止しておくと、よりスムーズに見えます
vsoApp.ScreenUpdating = False

‘ 1000個の四角形を作成し、配置
For i = 1 To 1000 ‘ ここで作成する図形の数を調整できます
xPos = (i Mod 40) 0.5 + 1
yPos = Int(i / 40) 0.5 + 1

vsoPage.Drop vsoMaster, xPos, yPos
Next i

‘ 処理終了時刻を記録
endTime = Timer

MsgBox “DeferRecalcを使った場合: ” & Format(endTime – startTime, “0.00”) & “秒”, vbInformation

ExitProcedure:
‘ ★★★ 重要なクリーンアップ処理 ★★★
‘ 必ずDeferRecalcとScreenUpdatingをFalseに戻す
If vsoApp.DeferRecalc = True Then
vsoApp.DeferRecalc = False
End If
If vsoApp.ScreenUpdating = False Then
vsoApp.ScreenUpdating = True
End If

‘ オブジェクトを解放
Set vsoMaster = Nothing
Set vsoPage = Nothing
Set vsoApp = Nothing
Exit Sub ‘ 正常終了時はエラーハンドラに行かないようにする

ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
GoTo ExitProcedure ‘ エラー発生時もクリーンアップ処理へ
End Sub

このコードを実行すると、一瞬で処理が完了し、一気に全ての図形が描画されるはずです。その速度差は歴然としているでしょう。

コードのポイントと注意点

  • `vsoApp.DeferRecalc = True` の設定: 処理の開始直後に設定します。
  • `vsoApp.ScreenUpdating = False` の併用: `DeferRecalc`は主に内部的な計算の保留ですが、`ScreenUpdating`は画面の描画更新そのものを停止します。これらを併用することで、VBA実行中の画面のちらつきがなくなり、ユーザー体験が向上します。
  • `vsoApp.DeferRecalc = False` の設定を忘れない: これが最も重要です! もし`True`にしたままVBAコードが終了してしまうと、Visio図面は更新されず、VBAで行った変更が画面に反映されません。Visioを一度閉じて開き直すまで、変更が見えない状態になってしまいます。
  • エラーハンドリングの重要性: `On Error GoTo ErrorHandler` を使って、VBAコードの途中でエラーが発生した場合でも、確実に`DeferRecalc = False`と`ScreenUpdating = True`に戻すようにしましょう。これがないと、Visioが「描画保留」状態のまま固まってしまう可能性があります。

なぜApplication.DeferRecalcが「極限の知見」なのか?

`Application.DeferRecalc`は単なる高速化テクニックではありません。これはVisioのオブジェクトモデルと、その内部的な計算・描画パイプラインに対する深い理解から生まれた、非常にパワフルな制御機構です。

Visioの図形は、ただの「絵」ではありません。それぞれが複雑な数式(ShapeSheet)を持ち、互いに参照し合い、依存関係を構築しています。例えば、コネクタは接続先の図形の位置に依存し、グループ内の図形はグループのサイズや位置に依存します。

`DeferRecalc = True`にすることで、Visioはこれらの数式評価と依存関係の更新(つまり「再計算」)を一時的に停止します。そして、`DeferRecalc = False`に戻した瞬間に、これまでの全ての変更を一括で解決し、最小限のコストで最新の状態に更新するのです。

これは、オブジェクトのライフサイクルとパフォーマンスの重みを熟知しているからこそ導き出せる、究極の最適化手法と言えるでしょう。このメカニズムを理解することは、Visio VBAを次のレベルに引き上げるための第一歩となるはずです。

陥りやすいエラーと対策

1. `DeferRecalc = False` を忘れてしまう:

  • 現象: VBAが完了しても図面が更新されない。Visioを再起動するまで変更が見えない。
  • 対策: `On Error GoTo` を使ったエラーハンドリングと、`Exit Sub`の前に必ず`False`に戻すクリーンアップ処理を記述する。

2. デバッグ中の挙動:

  • 現象: `DeferRecalc = True` の状態でステップ実行すると、画面が更新されないため、何が起こっているか分かりにくい。
  • 対策: デバッグ中は`DeferRecalc`を一時的にコメントアウトするか、短いループで試すなど、慎重に進める。あるいは、`DeferRecalc = True`にした後、必要に応じて`vsoApp.Redraw()`を呼び出して部分的に更新させることも可能だが、これは`DeferRecalc`の恩恵を減らすことになるため、基本的には避ける。

まとめ:Visio VBAの基本はバッチリですよ!

`Application.DeferRecalc`を使いこなすことで、皆さんは大規模なVisio図面を扱う際の「遅さ」という大きな壁を乗り越えることができるでしょう。
これは単なる高速化テクニックではなく、Visioの描画と計算の仕組みを理解し、VBAでそれを意図的に制御する能力を身につけた証です。

ここをクリアすれば、Visio VBAの基本はバッチリですよ!
この知識を活かして、皆さんのVisio自動化がさらに加速し、より効率的でパワフルなソリューションを構築できるようになることを心から願っています。

さあ、Visio VBAの次の扉を開き、極限の自動化の世界へ飛び込みましょう!

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