Visio VBAの「1セルずつ更新」はなぜ罪深いのか:GetFormulasU/SetFormulasUで描く高速化の極致
Visioで数百、数千のシェイプを扱う業務自動化ツールを作っているとき、多くのエンジニアが最初の壁にぶつかる。「処理が終わらない」という壁だ。
`Shape.Cells(“Width”).Formula = “10mm”`
このコードをループで回しているなら、今すぐその手を止めてほしい。Visioのオブジェクトモデルにおいて、個別のセル操作は「ドキュメントの再計算」と「UIの再描画」という重厚なオーバーヘッドをループの数だけ発生させているからだ。
今日は、Visioの描画エンジンを黙らせ、メモリ上で一気に処理を完結させる「`GetFormulasU` / `SetFormulasU`」という、プロフェッショナルだけが知る高速化の真髄を伝授する。
—
1. なぜ「1セルずつ」は遅いのか
Visioのセル操作は、単なるプロパティの書き換えではない。値が変更されるたびに、Visioは「この変更が他のセルにどう影響するか」という依存関係グラフを走査し、再計算を行う。
数個のシェイプなら誤差だが、大規模な図面でこれを行うと、CPUの大部分が「再計算待ち」に費やされる。我々が目指すべきは、「Visioのエンジンを極力休ませ、一括で叩き込んでから一度だけ再計算させる」という非同期的なアプローチだ。
—
2. 実装の極意:配列による一括処理
`GetFormulasU` と `SetFormulasU` は、対象となるシェイプとセルの名称(ローカル名ではなくUniversal Name)を配列として渡し、数式を一括でやり取りするメソッドである。
プロダクションコード例
以下のコードは、ページ内の全シェイプの「幅」と「高さ」を一括で取得し、特定の条件で更新するテンプレートだ。
Public Sub BatchUpdateShapes()
Dim vsoPage As Visio.Page
Dim vsoShapes As Visio.Shapes
Dim count As Long
Dim i As Long
‘ セル名の配列(Universal Nameを使用すること)
Dim cellNames(0 To 1) As String
cellNames(0) = “Width”
cellNames(1) = “Height”
Set vsoPage = ActivePage
Set vsoShapes = vsoPage.Shapes
count = vsoShapes.Count
If count = 0 Then Exit Sub
‘ 一括取得用の配列を定義
Dim formulaArray() As Variant
ReDim formulaArray(0 To count – 1, 0 To 1)
‘ 1. 一括読み込み:GetFormulasU
‘ 内部処理でループを回すより、この呼び出し一回で済む
vsoShapes.GetFormulasU cellNames, formulaArray
‘ 2. メモリ上での高速処理
For i = 0 To count – 1
‘ 例: 幅が50mm以上のシェイプを50mmに固定する
If Val(formulaArray(i, 0)) > 50 Then
formulaArray(i, 0) = “50mm”
formulaArray(i, 1) = “20mm”
End If
Next i
‘ 3. 一括書き込み:SetFormulasU
‘ ここでVisioが一度だけ再計算を行うため、爆速になる
vsoShapes.SetFormulasU cellNames, formulaArray
Debug.Print “全シェイプの更新が完了しました。”
End Sub
—
3. 現場で「バグ」を生ませないための鉄則
この手法は強力だが、取り扱いには注意が必要だ。現場でハマりやすいポイントを整理しておく。
- Universal Nameの徹底:
`Width` ではなく `Width` を使うのは当然だが、カスタムプロパティ(Shape Data)などは「Prop.RowName」という形式で指定する。日本語名で指定すると、OSのロケールが変わった瞬間にツールが全滅する。必ず「U」付きメソッドとUniversal Nameを使うこと。
- 例外処理とトランザクション:
数百のシェイプを一括処理中にエラーが発生すると、中途半端な状態の図面が残る。`ActiveDocument.BeginUndoScope` を活用し、一括処理を一つのUNDO単位としてラップせよ。
- データベース連携の注意:
外部DBから取得した値を数式に流し込む際、文字列のクォーテーション管理には細心の注意を払うこと。`Formula` には `”` が含まれる場合があるため、`Chr(34)` を活用し、確実に正しい数式文字列を生成すること。
—
4. 最後に:エンジニアとしての矜持
「動けばいい」コードは、メンテナンスの段階でエンジニアの首を絞める。`GetFormulasU/SetFormulasU` は、Visioの内部構造を理解しているという証明だ。
もし、貴方の作成しているツールが「砂時計アイコン」を見せ続けているなら、それは単なる技術不足ではない。Visioという巨大なオブジェクトモデルへの敬意が足りない証拠だ。
この一括処理を習得した今、貴方のツールは一段階上の次元へ到達する。次の開発では、ぜひこの「配列によるバッチ処理」を標準設計として組み込んでみてほしい。
健闘を祈る。
