【実務・中級編】【初心者向け】ページサイズを自動判別し、図面枠を中央に自動配置するリサイズ・スクリプト – Visio VBA解析バイブル

スポンサーリンク
スポンサーリンク

座標系を支配せよ:Visio VBAにおける「図面枠の自動中央配置」への設計思想

Visioの自動化プロジェクトにおいて、多くの開発者が最初に突き当たる「見えない壁」がある。それは、「ページサイズを変更した瞬間、図面枠(タイトルブロック)が左上に置き去りにされる」という、一見単純で、かつ極めて泥臭い問題だ。

多くの初学者は、ここで「シェイプの座標を力技で書き換える」という、場当たり的なコードを書き始める。しかし、それではプロフェッショナルとは呼べない。実務における自動化ツールに求められるのは、単なる「動くコード」ではない。「例外を許容し、メンテナンス性を担保し、描画エンジンの挙動を完全に制御する設計」だ。

本稿では、ページサイズの変化に追従し、図面枠を常に完璧な中央へと導くための、極限の設計思想と実装方法を伝授する。

1. なぜ「左上への偏り」は起きるのか? ―― 座標系とピンの正体

まず、問題の根本原因を理解しなければならない。Visioの座標系は、ページ全体のサイズ(`Page.Width`, `Page.Height`)に基づいているが、各シェイプの配置は「Pin(ピン)」と呼ばれる点によって制御されている。

ページサイズをA3からA4に変更したとき、シェイプの絶対座標が維持されたままページ幅が縮小されると、シェイプは相対的に「端」に押しやられたように見える。

ここで初心者が犯す最大のミスは、「シェイプの重心」と「ピンの位置」を混同することだ。
シェイプの `PinX` をページの `Width / 2` に設定しても、そのシェイプのピンが「左上」に設定されていれば、図面枠は中央から右下にズレる。

設計の鉄則:
「図面枠を中央に置く」とは、単に座標を合わせることではない。「図面枠のPin位置を、図形自身の中心(Center)に設定した上で、ページの幾何学的な中心を代入する」という2段階のプロセスを指すのだ。

2. 堅牢な設計:プロフェッショナルが守る3つの原則

業務ツールとして配布するコードを書く際、私は常に以下の3原則を課している。

① 識別子の抽象化(Nameに依存しない)

`If Shape.Name = “DrawingFrame” Then` といったコードは、今日この瞬間にゴミと化す。ユーザーが図形をコピー&ペーストした瞬間、名前は `DrawingFrame.1` に変わるからだ。
「Tag」プロパティを活用せよ。 `Shape.Tag = “TitleBlock”` と定義しておけば、名前の変化に左右されない堅牢なロジックが組める。

② 疎結合なロジック構成

「ページサイズ変更」と「図面枠の移動」を一つの関数に詰め込んではならない。

  • ページ設定を行う関数
  • 図面枠を特定する関数
  • 座標を計算して移動させる関数

これらを分離することで、ユニットテストが可能になり、将来的な仕様変更(例:図面枠を中央ではなく特定のグリッドに合わせる等)に柔軟に対応できる。

③ 描画パフォーマンスの制御

大規模な図面でループ処理を行う際、描画更新(ScreenUpdating)を止めなければ、処理速度は指数関数的に低下し、ユーザー体験を損なう。

3. 実装例:プロダクション・グレードの自動リサイズ・スクリプト

以下に、私が現場で推奨する、エラーハンドリングと保守性を兼ね備えたコードを示す。これをそのままコピペして使うのではない。この構造を模倣せよ。

Option Explicit

''' <summary>
''' ページサイズを更新し、特定のタグを持つ図面枠を中央に再配置するメインルーチン
''' </summary>
Public Sub OptimizePageLayout(ByVal targetWidth As Double, ByVal targetHeight As Double)
    Dim vsoPage As Visio.Page
    Dim vsoShape As Visio.Shape
    Dim errorOccurred As Boolean
    
    On Error GoTo ErrorHandler
    
    ' 高速化のための設定
    Application.ScreenUpdating = False
    Application.DeferUpdates = True
    
    Set vsoPage = ActivePage
    
    ' 1. ページサイズの変更
    ' ※単位はインチまたはメートルなど、プロジェクトの標準に従うこと
    vsoPage.PageSheet.CellsU("PageWidth").FormulaU = targetWidth
    vsoPage.PageSheet.CellsU("PageHeight").FormulaU = targetHeight
    
    ' 2. 図面枠の再配置
    ' ページ内の全シェイプを走査するのではなく、特定のTagを持つものを狙い撃ちにする
    For Each vsoShape In vsoPage.Shapes
        If vsoShape.Tag = "TitleBlock" Then
            Call CenterShapeOnPage(vsoShape, vsoPage)
        End If
    Next vsoShape

CleanUp:
    ' 設定を元に戻す(これを忘れるとVisioの挙動が不安定になる)
    Application.DeferUpdates = False
    Application.ScreenUpdating = True
    Exit Sub

ErrorHandler:
    errorOccurred = True
    MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical, "Architecture Error"
    Resume CleanUp
End Sub

''' <summary>
''' 指定されたシェイプをページの幾何学的中心に配置する。
''' ピンの位置を自動調整することで、形状のサイズに関わらず完璧な中央配置を実現する。
''' </summary>
Private Sub CenterShapeOnPage(ByRef targetShape As Visio.Shape, ByRef targetPage As Visio.Page)
    On Error Resume Next ' 個別のシェイプ操作失敗が全体を止めないようガード
    
    ' ステップ1: ピンの位置をシェイプの中心(Width/2, Height/2)に強制設定
    ' これにより、PinX/PinYへの代入が「図形の中心」を意味するようになる
    targetShape.CellsU("PinX").FormulaU = "Width / 2"
    targetShape.CellsU("PinY").FormulaU = "Height / 2"
    
    ' ステップ2: ページの中心座標を計算して代入
    ' FormulaUを使用することで、Visioの内部単位による計算誤差を最小限に抑える
    targetShape.CellsU("PinX").FormulaU = targetPage.PageSheet.CellsU("PageWidth").Formula
    targetShape.CellsU("PinY").FormulaU = targetPage.PageSheet.CellsU("PageHeight").Formula
    
    If Err.Number <> 0 Then
        Debug.Print "Shape centering failed for: " & targetShape.Name
    End If
    On Error GoTo 0
End Sub

4. アーキテクトの視点:外部データ連携における「罠」

もし、このスクリプトをExcelやデータベース(SQL Server等)から取得した「設計規格」に基づいて動かそうとしているなら、さらなる注意が必要だ。

1. 型の不一致を許さない:
Excelから渡される数値は、しばしば `Variant/Double` だが、Visioの `CellsU().FormulaU` は文字列としての式を期待する場合がある。数値として渡すのか、`”10.5 in”` のように単位を含めた文字列として渡すのか、インターフェースを厳格に定義せよ。
2. トランザクションの概念:
データベースの値を参照してページサイズを変える際、もし途中でエラーが起きたらどうするか?「サイズだけ変わって、図面枠がズレたまま」という状態は、データの整合性が崩れたことを意味する。大規模な自動化では、変更前に現在の状態をバックアップ(あるいは一時的なファイルに保存)する、あるいはエラー時に `Undo` が効く範囲内で処理を完結させる設計が求められる。

結論

Visio VBAにおける自動化の本質は、単なる「操作の記録」ではない。
「オブジェクトの属性(Tag)を管理し、幾何学的な原理(Pin/Coordinate)を理解し、例外(Error Handling)を制御する」ことにある。

この視点を持ってコードを書くか、それとも単に「動けばいい」と妥協するか。その差が、数ヶ月後のメンテナンスコスト、そしてエンジニアとしての評価を決定づけるのだ。

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