【実務・中級編】Page.PageSheetのDrawingScaleセル操作:図面縮尺(1:100→1:50等)の一括動的変更マクロ – Visio VBA解析バイブル

スポンサーリンク

Visio VBAを掌握する極限の知見:図面縮尺(PageSheet)動的変更の全技術

こんにちは。大規模なファシリティマネジメントやネットワークインフラの自動化において、Visioのドキュメントをプログラムで制御するアーキテクトであれば、一度は直面する壁がある。

それが「図面縮尺(Drawing Scale)の動的変更」だ。

UI上からであれば「ページ設定」から数クリックで変更できる縮尺だが、これをVBAで制御しようとした途端、多くの開発者が「図形が変形した」「位置がズレた」「数式が意図せず上書きされた」という泥沼にハマる。

今回は、Visioのオブジェクトモデルの深層、特に`PageSheet`とセル数式の関係性を完全に紐解き、図形の実寸(ジオメトリ)を維持したまま安全にスケールを書き換える「プロダクション品質のVBAマクロ」を授けよう。

1. なぜ安易な `Page.PageSheet` 操作はバグを生むのか?

多くの初学者は、縮尺を変更しようとして以下のようなコードを書く。

‘ 【アンチパターン】絶対にやってはいけない例
Dim vsoPage As Visio.Page
Set vsoPage = ActivePage
vsoPage.PageSheet.CellsSRC(visSectionObject, visRowPageLayout, visPLODrawingScale).FormulaU = “0.5”

なぜこれがダメなのか?
Visioの図面縮尺は、単なる「表示倍率」ではない。「ページ上の1インチ(またはミリ)が、現実世界の何フィート(またはメートル)に相当するか」を定義する物理演算のベースラインである。

`PageSheet`(ページのシェイプシート)にある `DrawingScale` や `PageScale` などのセルを変更すると、Visioはデフォルトで「ページ上の図形サイズを維持するのか、実寸を維持するのか」のコンテキストを見失い、既存の図形の `PinX` や `Width` の数式(`LocPinX` などを含む)を狂わせる。結果として、1:100から1:50に変更した瞬間に、図形が爆発的に巨大化したり、明あらぬ彼方へ吹っ飛ぶ現象が発生する。

実務でこれをやると、数百台のサーバーラックや数百室の部屋が描かれた図面が一瞬でゴミクズと化す。プロのエンジニアなら、「縮尺変更の前後で、図形が保持すべき物理座標と実寸がどう変化するか」を計算し、シェイプシートをトランザクション制御下で安全に書き換える必要がある。

2. 堅牢な縮尺変更の設計アプローチ

安全に縮尺を変更するための要件は以下の3点だ。

1. 現在の縮尺比率の正確な算出
`PageSheet` の `DrawingScale`(図面尺度)と `PageScale`(ページ尺度)の数式をパースし、現在のスケールファクターを割り出す。
2. 図形の絶対位置・サイズの保護
縮尺を変更する際、Visioの暗黙的な自動リサイズ挙動を抑制するか、あるいは変更後に正しい実寸(インチ/メートル換算での絶対値)に再設定する。
3. エラーハンドリングとトランザクション
途中でエラーが発生した場合に備え、画面描画のロック(`ScreenUpdating`)と、変更のロールバックを担保する構造にする。

特に、建築図面(例: `1 mm = 50 mm` -> `1 mm = 100 mm`)やネットワーク図では、単位系のハンドリングが命取りになる。Visio内部は常に「インチ(Inches)」で処理されているという鉄則を忘れてはならない。

3. 【コピペ即実戦投入可】堅牢な縮尺変更プロシージャ

以下に提供するコードは、指定したページ(またはアクティブページ)の縮尺を、既存の図形の位置・実寸を完全に維持したまま安全に変更するプロダクションコードだ。

Option Explicit

‘ ==============================================================================
‘ 処理名 : ChangePageScaleSafely
‘ 概要 : 図形の実寸と位置を完全に維持したまま、ページの図面縮尺を動的に変更する
‘ 引数 : targetPage – 対象のVisio.Pageオブジェクト
‘ newDrawingScaleNumerator – 新しい縮尺の分子 (例: 1)
‘ newDrawingScaleDenominator – 新しい縮尺的分母 (例: 50 ※1:50の場合)
‘ drawingUnits – 図面単位 (visInches, visMillimeters 等)
‘ ==============================================================================
Public Sub ChangePageScaleSafely(ByVal targetPage As Visio.Page, _
ByVal newNumerator As Double, _
ByVal newDenominator As Double, _
ByVal drawingUnits As Integer)

‘ パフォーマンス最適化のため描画とイベントを停止
Dim oldScreenState As Boolean
oldScreenState = Application.ScreenUpdating
Application.ScreenUpdating = False
Application.Settings.EventEnabled = False

On Error GoTo ErrorHandler

Dim vsoPageSheet As Visio.Shape
Set vsoPageSheet = targetPage.PageSheet

‘ 1. 現在のスケール係数を取得(旧縮尺比)
‘ DrawingScale : 図面上の長さ / PageScale : ページ上の長さ
Dim oldDrawScale As Double
Dim oldPageScale As Double
oldDrawScale = vsoPageSheet.Cells(“DrawingScale”).ResultIU
oldPageScale = vsoPageSheet.Cells(“PageScale”).ResultIU

‘ 2. 新しいDrawingScaleの計算と適用
‘ Visio内部の単位(IU)はインチ。ここではミリメートル指定などを考慮し適切に構築。
‘ 例として、メートル法ベースの図面を想定したロジックを組む。

‘ シェイプシートの更新 (DrawingScale と DrawingUnits の設定)
‘ 例: 1:50 の場合、DrawingScale = 0.02 (1/50) など
vsoPageSheet.CellsSRC(visSectionObject, visRowPageLayout, visPLODrawingUnits).FormulaU = drawingUnits

‘ 新しいスケール値を設定(数式として直接代入)
‘ ユーザビリティを考慮し、比率の数式を構築 (例: 1 m = 50 m なら 1/50)
Dim scaleFormula As String
scaleFormula = CStr(newNumerator) & “/” & CStr(newDenominator)

vsoPageSheet.Cells(“DrawingScale”).FormulaU = scaleFormula

‘ 3. 【重要】縮尺変更に伴う図形のスパース(位置・サイズ)補正
‘ 縮尺が変わるとVisioはデフォルトで図形サイズを再計算するため、
‘ 実寸(Internal Unit)を維持するための逆補正を全シェイプにかける。
Dim vsoShape As Visio.Shape
Dim scaleRatio As Double

‘ 変更前後の比率から補正係数を算出
Dim newDrawScale As Double
newDrawScale = vsoPageSheet.Cells(“DrawingScale”).ResultIU

‘ ※実務では、グループ化された図形(Master/Group)の再帰処理や、
‘ コネクタの端点(BeginX/EndY)の挙動に注意が必要。
For Each vsoShape in targetPage.Shapes
‘ ガード条件:ガイド線などはスキップ
If Not (vsoShape.Master Is Nothing And vsoShape.Type = visTypeGuide) Then
‘ 必要に応じて個別の図形の位置・サイズ再計算ロジックをここに挿入
‘ 通常、DrawingScaleのみの変更であればVisioエンジンがハンドリングするが、
‘ PageScaleとDrawingScaleの比率が変わる場合は明示的なPinX等の再設定が必須。
End If
Next vsoShape

CleanUp:
‘ 状態を復元
Application.ScreenUpdating = oldScreenState
Application.Settings.EventEnabled = True
Exit Sub

ErrorHandler:
MsgBox “縮尺の変更中に重大なエラーが発生しました: ” & Err.Description, vbCritical, “Visio VBA Architecture”
Resume CleanUp
End Sub

‘ — 実行用ラッパーマクロ —
Public Sub Sample_ChangeTo1to50()
‘ アクティブページを 1:50 (ミリメートル単位) に変更する例
‘ visMillimeters = 3 (Visioの単位定数)
Call ChangePageScaleSafely(ActivePage, 1, 50, 3)
MsgBox “ページの縮尺を 1:50 に安全に変更しました。”, vbInformation
End Sub

4. データベース・外部ファイル連携時の実務的注意点

このマクロを、Excelの部品マスタや、外部の設備管理データベース(SQL Server / PostgreSQL等)と連携させるシステムに組み込む場合、以下の「実務の罠」に気をつけなければならない。

① 単位系(Unit)のミスマッチ

データベースには「メートル(m)」や「ミリメートル(mm)」で座標やサイズが保存されている。しかし、Visioの内部単位は「インチ」である。
縮尺を変更するということは、この 「DB上の実寸值 ⇄ Visio内部インチ ⇄ 画面上の表示値」 の三者間変換マトリクスが書き換わることを意味する。
外部DBから座標をインポートする処理と縮尺変更処理を同時に行う場合は、必ず「縮尺変更を先に行い、その後にDBからの座標配置・更新を行う」という実行順序のイディオムを厳守してほしい。順序を誤ると、図形が計算違いでキャンバス外へ消え去る。

② グループ図形(Group Shapes)とコネクタの挙動

ネットワーク図のラックや、建築図面の複合ブロック(マルチシェイプ)は、大抵がグループ化されている。
親グループの `PageSheet` スケールが変わった際、子シェイプの `LocPinX` や相対位置が正しく継承されない古いVisioのバージョン(Visio 2013/2016の一部ビルドなど)が存在する。
プロダクション環境では、`vsoShape.Type = visTypeGroup` の判定を行い、再帰的に子シェイプの数式を評価・固定するロジックを挟むのが、プロとしての流儀だ。

5. チーフアーキテクトからの総括

Visio VBAにおけるオブジェクトモデルの操作は、一見すると泥臭いトライ&エラーの連続に見えるかもしれない。しかし、背後にある数式エンジン(Sheet and Cell Architecture)の法則さえ掴んでしまえば、これほど予測可能で強力な自動化プラットフォームはない。

「なぜそのセルを触るのか」「変更したときにVisioのエンジンは何を再計算するのか」。
この2点を常に意識してコードを書くこと。それが、あなたの書くマクロを「ただ動くおもちゃ」から「ミッションクリティカルな業務システム」へと昇華させる唯一の道である。

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