Visio VBAを掌握する極限の知見:PageSheetへの直接介入による動的レイアウト制御と特殊アスペクト比の極意
VisioのデフォルトUIは、定型的なビジネスプロセスやネットワーク図を描くには優れているが、大規模なプラント図、変則的なインフォグラフィック、あるいは外部システムから自動生成されるリアルタイム・ダイアグラムのカンバスとしては、あまりにも窮屈だ。
UI上の「ページ設定」ダイアグラムは、内部的には1枚の「図面シェイプ(PageSheet)」が保持する数式群のラッパーに過ぎない。この真実に気づいた者だけが、Visioのレイアウトエンジンを完全に手中に収めることができる。
今回は、`Page.PageSheet` を介した低レイヤーのセル操作により、GUIでは設定不可能な特殊アスペクト比や動的スケールをコードベースでねじ込む極限のテクニックを公開する。
—
1. PageSheetアーキテクチャの深層:なぜ「プロパティ操作」では限界があるのか
Visio VBA初学者は、ページサイズを変更しようとして以下のようなコードを書きがちだ。
‘ 【アンチパターン】これではカスタムアスペクト比の動的制御で破綻する
ActivePage.PageSheet.CellsU(“PageWidth”).FormulaU = “100 mm”
一見、これで動くように見える。しかし、`PageWidth` や `PageHeight` を単一で書き換えると、Visioの連動計算(Dependency Graph)により、意図しない `PageScale` や `DrawingScale` の自動補正が走り、結果として意図した物理寸法と論理寸法の乖離を生む。さらに、プリンタードライバの用紙サイズ制約が背後で絡み合い、予期せぬエラーやレイアウト崩壊を引き起こすのだ。
シニアエンジニアが理解すべきは、PageSheetは通常の `Shape` オブジェクトと何ら変わらないという事実である。つまり、セルの評価順序、単位系(U = Universals)、そしてキャッシュのライフサイクルを完全に制御下におかなければならない。
—
2. 実装コード:特殊アスペクト比と動的スケールの完全制御
以下のコードは、外部システム(DBやAPI)から受け取った任意のピクセル比率や特殊な物理寸法を、Visioの計算エンジンをハングアップさせずに `PageSheet` へ流し込むための実用プロシージャである。
オブジェクトの解放、エラーハンドリング、そしてトランザクション的な一括処理(`EventEnabled` の一時無効化)を網羅したプロダクション品質で記述している。
Option Explicit
‘ ==============================================================================
‘ 処理名: ApplyCustomPageGeometry
‘ 概要 : PageSheetへの直接アクセスにより、特殊アスペクト比とカスタムスケールを適用する
‘ 備考 : UIの制約をバイパスし、ミリメートル単位でカンバスを完全に支配する
‘ ==============================================================================
Public Sub ApplyCustomPageGeometry(ByVal targetPage As Visio.Page, _
ByVal widthMM As Double, _
ByVal heightMM As Double, _
ByVal drawingScale As Double)
Dim vsoPageSheet As Visio.Shape
Dim originalEventState As Integer
‘ 1. 描画イベントと画面更新を一時停止(パフォーマンスの極限最適化と無限ループ防止)
originalEventState = Application.EventEnabled
Application.EventEnabled = False
Application.ScreenUpdating = False
On Error GoTo ErrorHandler
‘ 2. PageSheetの取得(裏側のマスターシェイプにアクセス)
Set vsoPageSheet = targetPage.PageSheet
‘ 3. セル値のトランザクション書き込み
‘ 単位系トラブルを防ぐため、常にUniversals構文(“FormulaU”)を使用する
With vsoPageSheet
‘ ページ幅と高さをミリメートル単位で直結
.CellsU(“PageWidth”).FormulaU = CStr(widthMM) & ” mm”
.CellsU(“PageHeight”).FormulaU = CStr(heightMM) & ” mm”
‘ 印刷用スケールと図面スケールの同期(1:1等の特殊比率を強制適用)
‘ 例: 1mm (Drawing) = drawingScale mm (Page)
.CellsU(“DrawingScale”).FormulaU = “1 mm”
.CellsU(“PageScale”).FormulaU = CStr(drawingScale) & ” mm”
‘ プレフィックスや余白の自動調整機能を無効化(固定レイアウト化)
.CellsU(“UIVisibility”).FormulaU = “0”
End With
Debug.Print “PageSheet Geometry Updated Successfully: ” & widthMM & “x” & heightMM & “mm”
CleanUp:
‘ 4. 状態の復元とメモリの明示的解放
Application.EventEnabled = originalEventState
Application.ScreenUpdating = True
Set vsoPageSheet = Nothing
Exit Sub
ErrorHandler:
MsgBox “PageSheetの書き込みに失敗しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“説明: ” & Err.Description, vbCritical, “Visio VBA 致命的エラー”
Resume CleanUp
End Sub
—
3. コードの急所:シニアエンジニアが押さえるべき3つの技術的ポイント
① `Application.EventEnabled = False` による依存関係ループの遮断
PageSheetの数式(例: `PageWidth` と `PageScale`)を書き換える際、Visioは内部で再計算イベントを連続して発生させる。これが他のアドインや図形側の `OnShapeChange` イベントと競合すると、VBAランタイムが沈黙するか、最悪の場合はVisio本体がクラッシュする。一連の代入の直前でイベントを殺し、最後に復元するイディオムは、大規模自動化における必須の防衛策である。
② `FormulaU` と Universals 構文の徹底
`Formula` プロパティを使うと、実行しているPCのOS言語設定(日本語、英語など)によって `”100 mm”` や `”100 mm”` の解釈が狂い、実行時エラー(構文エラー)を引き起こす。コードは必ず英数字と標準キーワードで構成される `FormulaU` を使用し、単位も明示的に文字列結合すべきである。
③ COMオブジェクトの参照リーク防止
`targetPage.PageSheet` を呼び出した瞬間、背後でCOMのインターフェースポインタが生成される。プロシージャの最後で `Set vsoPageSheet = Nothing` を明示的に行わなければ、Visioのプロセス内にガベージが残り、連続処理時にメモリリークを引き起こす。長期稼働するシステム連携基盤では致命傷となるポイントだ。
—
4. システム間連携(API/DB)への応用
この手法の真価は、Web APIやRDBから非同期で送られてくる「画面解像度比率」や「特殊な設計図面サイズ(建築パースの変則アスペクト比など)」を、人間の介在なしに一瞬でVisioのカンバスに同期させられる点にある。
例えば、C# (.NET) から COM Interop 経由でこのVBAマクロを叩く、あるいはVBA自身が `MSXML2.DOMDocument` や `WinHttp.WinHttpRequest.5.1` を叩いてJSONを取得し、動的にPageSheetを書き換えることで、「データ駆動型の完全自動製図パイプライン」が完成する。
GUIの呪縛を断ち切り、PageSheetの底流にある数式を支配せよ。それこそが、真のVisioインテグレーションである。
