【実務・中級編】Cell操作のボトルネックを打破:Shape.GetFormulasUとSetFormulasUによる複数セルの一括高速読み書き – Visio VBA解析バイブル

スポンサーリンク

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という巨大なオブジェクトモデルへの敬意が足りない証拠だ。

この一括処理を習得した今、貴方のツールは一段階上の次元へ到達する。次の開発では、ぜひこの「配列によるバッチ処理」を標準設計として組み込んでみてほしい。

健闘を祈る。

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