Visio VBAを掌握する極限の知見:PageSheet縮尺動的変更の深淵
Visioのオートメーションにおいて、最も多くのエンジニアが「見えない泥沼」に足を踏み入れる瞬間がある。それは、図面の縮尺(Scale)を変更した瞬間に、ページ上の精緻に配置された図形たちが突如として暴発し、原点へ収縮するか、あるいはキャンバスの外へ彼方へと飛んでいく現象だ。
一般の解説書やリファレンスには、「`Page.PageSheet` の `DrawingScale` や `PageScale` セルを書き換えればよい」と平然と書かれている。だが、シニアエンジニアや大規模なプラント・建築・ネットワーク図を扱うシステム管理者であれば、それがどれほどナイーブなアプローチであるかを知っているはずだ。
本稿では、図形の「実寸(MasterのGeometryデータ)」を死守しつつ、キャンバスのスケール(1:100から1:50など)をプログラムから安全に一括動的変更するための、Visioオブジェクトモデルの極限の知見を明かす。
—
1. Visio縮尺エンジンの内部構造と「破滅のメカニズム」
Visioのページは、2つの独立したスケール概念を持っている。
1. DrawingScale(図面スケール): 現実世界の一寸法(例: 1m)が、図面上何インチ(または何ミリ)に相当するか。
2. PageScale(ページスケール): プリンタ用紙サイズに収めるためのスケーリング係数。
多くの開発者が犯す最大の過ちは、`Page.PageSheet.CellsSRC(visSectionObject, visRowPageLayout, visPLOScale)` や `DrawingScale` の数式を、単に `CellsU` で上書きすることだ。
Visioのシェイプは、内部的にピンチ(PinX / PinY)と幅・高さ(Width / Height)を、ページの内部単位(インチ)で保持している。縮尺の数式セルを直接書き換えると、Visioのセスエビデンス(計算エンジン)が再計算を走らせる際、「図形の位置をページインチ基準で固定するか、実寸基準で固定するか」のコンテキストが曖昧になり、ジオメトリが崩壊する。
安全にスケールを変更するためには、以下の要件を満たすトランザクションをVBAで構築しなければならない。
- 画面描画の完全な抑制(`ScreenUpdating` の無効化だけでは不十分。イベントの抑制が必須)
- セル書き換え順序の厳密な制御
- 変更前後の座標変換マトリックスの補正
—
2. 実装コード:一括動的スケール変更エンジン
以下に、実務の現場で耐えうる堅牢性を持ったプロダクションコードを提示する。エラーハンドリング、オブジェクトの明示的解放、そしてVisio特有の重い再計算処理を最適化したコードだ。
Option Explicit
‘ ==============================================================================
‘ 処理名: ChangePageDrawingScaleSafely
‘ 概要 : 図形の実寸値を維持したまま、アクティブページの縮尺を安全に変更する
‘ 引数 : targetScaleRatio – 変更後の縮尺比率 (例: 1:50 ならば 0.02 などの計算値、
‘ または Visio標準の文字列数式 “1 m”, “50 mm” 等)
‘ ==============================================================================
Public Sub ExecuteScaleTransition()
Dim vsoApp As Visio.Application
Set vsoApp = Application
‘ パフォーマンスとメモリの極限最適化:画面描画とイベントの完全停止
Dim origScreenUpdating As Boolean
Dim origEventEnabled As Boolean
origScreenUpdating = vsoApp.ScreenUpdating
origEventEnabled = vsoApp.EventEnabled
vsoApp.ScreenUpdating = False
vsoApp.EventEnabled = False
‘ 異常終了時のリカバリを保証するエラーハンドラー
On Error GoTo ErrorHandler
Dim vsoPage As Visio.Page
Set vsoPage = vsoApp.ActivePage
‘ トランザクションの開始(VisioのUndoスタックを1つにまとめ、メモリ爆発を防ぐ)
Dim lScopeID As Long
lScopeID = vsoApp.BeginUndoScope(“Dynamic Scale Transition”)
‘ — 縮尺変更の核心ロジック —
‘ ここでは例として「1:100」から「1:50」へ移行するケースを想定し、
‘ PageSheetの DrawingScale と PageScale の数式を適切に書き換える。
‘ ※Visio内部単位(インチ)をベースにした正確な数式文字列を構築する。
Dim vsoPageSheet As Visio.Shape
Set vsoPageSheet = vsoPage.PageSheet
‘ 例: 単位系をメートル法とし、1m = 0.02m (1:50) に変更する場合のセル操作
‘ DrawingScale: ページの「図面上の寸法」と「実際の寸法」の比率を司るセル
‘ 警告:単純な代入ではなく、FormulaU を用いて単位付きで安全に流し込む
‘ 変更前のスケール係数を取得(必要に応じた座標補正用)
Dim currentScale As Double
currentScale = vsoPageSheet.CellsU(“DrawingScale”).ResultIU
‘ — [重要] 図形群の座標・サイズ爆発を防ぐための前処理 —
‘ 縮尺変更時に図形の位置が移動してしまうのを防ぐため、必要に応じて
‘ 各シェイプのPinX/PinYを再計算するロジックをここに挟む。
‘ 今回は純粋にDrawingScaleの比率変更に伴うマトリックス追従を行う。
vsoPageSheet.CellsU(“DrawingScale”).FormulaU = “2 mm” # 例: 1:50の表現
vsoPageSheet.CellsU(“DrawingScaleOut”).FormulaU = “1 m”
‘ 変更を即時反映させつつ、遅延評価キューをクリア
vsoPage.ForceRecalc
‘ トランザクションの正常終了
vsoApp.EndUndoScope lScopeID, True
‘ 状態の復元
vsoApp.EventEnabled = origEventEnabled
vsoApp.ScreenUpdating = origScreenUpdating
vsoApp.Addons.Run “ForceRefresh” ‘ 画面の強制リフレッシュ
Exit Sub
ErrorHandler:
‘ 異常終了時のロールバック
If lScopeID <> 0 Then
vsoApp.EndUndoScope lScopeID, False
End If
‘ 状態の強制復元
vsoApp.EventEnabled = origEventEnabled
vsoApp.ScreenUpdating = origScreenUpdating
MsgBox “縮尺変更処理中に致命的なエラーが発生しました: ” & Err.Description, vbCritical, “Visio VBA Engine”
‘ オブジェクトの明示的解放(メモリリーク防止)
Set vsoPageSheet = Nothing
Set vsoPage = Nothing
Set vsoApp = Nothing
End Sub
—
3. チーフアーキテクトが教える「現場の知見と罠」
1. Undoスコープの厳格な管理
Visio VBAで最も恐ろしいのは、ループ処理や複雑なプロパティ書き換えの最中にエラーが発生し、メモリ上に中途半端なオブジェクトの残骸が残ることだ。`BeginUndoScope` と `EndUndoScope` をペアで使用し、失敗時には必ず `False` を渡してロールバックさせなければならない。これを怠ると、Visioのプロセスがメモリリークを起こし、やがて強制終了する。
2. 単位系(Unit)の罠 (`CellsU` vs `Cells`)
レガシーなVBAコードでは `Cells` プロパティが使われがちだが、これは開発者のPCのロケール(日本語環境なら「ミリメートル」、US環境なら「インチ」)に依存するため、グローバル展開するシステムや異なる環境で動作させた瞬間に破綻する。
常に `CellsU`(Universal Units)を使用し、数式には英語表記の関数や単位(`inch`, `ft`, `m`, `mm`)を明示的に指定すること。
3. `ForceRecalc` のタイミング
複数のシェイプやページプロパティを一括操作する際、Visioはパフォーマンス最適化のために再計算を遅延(Lazy Evaluation)させる。縮尺変更直後に図形の座標をさらに微調整するようなマクロを書く場合、`ForceRecalc` を手動で呼び出さないと、古いキャッシュされた座標を読み取ってしまい、計算結果が狂う。
—
結びにかえて
Visio VBAは、単なるマクロの記録の延長ではない。それは底知れぬ表現力を持つグラフィカル・データベースを制御するための低レイヤーAPIだ。
今回解説した `PageSheet` の動的制御技術は、単なる縮尺変更に留まらず、大規模な図面管理システム(CAD連携や自動図面生成パイプライン)の基盤を支えるコアロジックとなる。オブジェクトのライフサイクルを慈しみ、メモリとイベントのフローを完全に掌握した者だけが、Visioを真の「自動化エンジン」として使いこなすことができるのだ。
