序説:紙と図面の「不都合な真実」を調律する
現場の最前線でVisioを扱ってきた諸君なら、一度は絶望したことがあるはずだ。「画面上では完璧に見える図面が、印刷した瞬間に余白だらけになる」、あるいは「PDF出力時にページ端が欠落する」という、あの忌々しい現象だ。
この問題の本質は、Visioというアプリケーションの二重構造にある。Visioのページには、論理的な「図面サイズ(Drawing Page Size)」と、物理的な「プリンタ用紙サイズ(Printer Paper Size)」という、独立した二つの空間定義が存在する。これらが一致していない状態、すなわち「幾何学的な不整合」こそが、業務自動化における最大のボトルネックだ。
多くの凡庸なエンジニアは、GUIの「ページ設定」ダイアログで場当たり的な修正を繰り返す。しかし、我々チーフアーキテクトの仕事は、その不整合をプログラムによって検知し、ミリ単位の誤差も許さず自動的に矯正する堅牢なロジックを組むことにある。
本稿では、ShapeSheetの深淵を覗き込み、VBAを用いて全ページの整合性を担保する「監査・自動修正ツール」の設計思想を解説する。
—
1. ShapeSheet:幾何学的定義の核心部
Visioのページ設定を操作する際、Pageオブジェクトのプロパティを叩くだけでは不十分だ。真の制御は、各ページが内部に保持する仮想的なスプレッドシート、「ShapeSheet」の`Print Properties`セクションおよび`Page Properties`セクションで行う。
特に注目すべきは以下のセルだ。
- PageWidth / PageHeight: 図面自体の論理サイズ。
- PaperWidth / PaperHeight: 物理的な出力用紙のサイズ。
- PrintPageOrientation: 印刷の向き(1: 縦, 2: 横)。
これらが互いに参照し合っていない、あるいはハードコードされた数値で乖離している場合、印刷事故は必然となる。
—
2. 実装:ページ設定監査ツールの極致
以下に、全ページをスキャンし、図面サイズと用紙サイズの不一致を検出・修正するコードを示す。ここでは、パフォーマンスを最大化するためにイベント抑制と再計算の遅延制御を組み込んでいる。
Option Explicit
‘ —————————————————————————–
‘ 構造体定義:不整合レポート用
‘ —————————————————————————–
Private Type PageAuditResult
PageName As String
IsMismatched As Boolean
CurrentDrawingSize As String
CurrentPaperSize As String
End Type
‘ —————————————————————————–
‘ メインルーチン:図面と用紙サイズの整合性監査および強制同期
‘ —————————————————————————–
Public Sub AuditAndSyncPageSettings()
Dim vsoApp As Visio.Application
Dim vsoDoc As Visio.Document
Dim vsoPage As Visio.Page
Dim vsoPageSheet As Visio.Shape
Set vsoApp = Visio.Application
Set vsoDoc = vsoApp.ActiveDocument
‘ パフォーマンス最適化:画面更新とイベント発生を抑制
vsoApp.ScreenUpdating = False
vsoApp.EventsEnabled = False
vsoApp.DeferRecalc = True ‘ ShapeSheetの再計算を遅延させる
On Error GoTo ErrorHandler
Debug.Print “— Page Audit Start: ” & vsoDoc.Name & ” —”
For Each vsoPage In vsoDoc.Pages
‘ 背景ページはスキップ(必要に応じてロジックを変更)
If vsoPage.Background = False Then
Set vsoPageSheet = vsoPage.PageSheet
‘ 監査と修正の実行
Call SyncDrawingToPrinter(vsoPage, vsoPageSheet)
End If
Next vsoPage
Debug.Print “— Page Audit Completed —”
CleanUp:
‘ 状態の復元(重要:これを忘れるとVisioの動作が不安定になる)
vsoApp.DeferRecalc = False
vsoApp.EventsEnabled = True
vsoApp.ScreenUpdating = True
‘ 明示的なオブジェクト解放
Set vsoPageSheet = Nothing
Set vsoPage = Nothing
Set vsoDoc = Nothing
Set vsoApp = Nothing
Exit Sub
ErrorHandler:
Debug.Print “Error in AuditAndSyncPageSettings: ” & Err.Description
Resume CleanUp
End Sub
‘ —————————————————————————–
‘ サブルーチン:ShapeSheetセルレベルでの同期
‘ —————————————————————————–
Private Sub SyncDrawingToPrinter(ByRef vsoPage As Visio.Page, ByRef vsoPageSheet As Visio.Shape)
‘ ShapeSheetのセル定数
‘ visSectionObject = 1, visRowPage = 10
Dim drawingWidth As Double
Dim paperWidth As Double
Dim drawingHeight As Double
Dim paperHeight As Double
‘ セル値の取得 (Internal Units: Inches)
drawingWidth = vsoPageSheet.CellsU(“PageWidth”).ResultIU
drawingHeight = vsoPageSheet.CellsU(“PageHeight”).ResultIU
paperWidth = vsoPageSheet.CellsU(“PaperWidth”).ResultIU
paperHeight = vsoPageSheet.CellsU(“PaperHeight”).ResultIU
‘ 許容誤差 0.01インチ以内か判定
If Abs(drawingWidth – paperWidth) > 0.01 Or Abs(drawingHeight – paperHeight) > 0.01 Then
Debug.Print “[MISMATCH FOUND] Page: ” & vsoPage.Name
‘ 同期処理:図面サイズを用紙サイズに強制的に合わせる
‘ FormulasUを使用し、セルの依存関係(Formula)を上書きする
vsoPageSheet.CellsU(“PageWidth”).FormulaU = “PaperWidth”
vsoPageSheet.CellsU(“PageHeight”).FormulaU = “PaperHeight”
‘ 印刷の向きも、用紙の縦横比から自動判定させる設定へ
‘ 0: 自動, 1: 縦, 2: 横
vsoPageSheet.CellsU(“PrintPageOrientation”).FormulaU = _
“IF(PaperWidth>PaperHeight,2,1)”
Debug.Print ” -> Synchronized drawing size to printer paper size.”
Else
Debug.Print “[OK] Page: ” & vsoPage.Name
End If
End Sub
—
3. 技術的深掘り:なぜ `FormulaU = “PaperWidth”` なのか?
上記のコードで、私は単に数値を代入するのではなく、`FormulaU = “PaperWidth”` という文字列を代入している。ここにシニアエンジニアとしての「設計思想」が込められている。
1. 動的追従性の確保:
数値を直接代入(`ResultIU`への書き込み)した場合、将来的にユーザーがプリンタ設定を変更しても図面サイズは追従しない。しかし、セルに「式(Formula)」を埋め込めば、用紙サイズが変更された瞬間に図面サイズも自動再計算される「インテリジェントなページ」へと昇華する。
2. 国際化対応(Universal Syntax):
`Cells` ではなく `CellsU`、`Formula` ではなく `FormulaU` を使用するのは、多言語環境下での動作を保証するためだ。日本語版のVisioで「幅」というローカル名に依存するコードは、グローバル展開されるシステムではゴミに等しい。
—
4. レガシー環境とメモリ管理の規律
Visio VBAは、COM(Component Object Model)の深い階層の上で動いている。ループ内で `PageSheet` オブジェクトを繰り返し生成・参照する場合、ガベージコレクションに頼るのではなく、明示的に `Nothing` を代入して参照カウントを下げるのがプロフェッショナルの作法だ。
また、Windows APIを用いた `DocumentProperties` の操作を併用することで、VBAの標準機能では届かない「プリンタドライバ固有の設定(給紙トレイの指定など)」まで制御可能だが、保守性を考慮し、まずはShapeSheetでの解決を優先すべきである。
—
結言:自動化の真価
ページ設定の不整合を正すことは、単なる「見た目の修正」ではない。それは、ドキュメントのライフサイクルにおける「信頼性」の構築だ。
優れたアーキテクトは、GUIの向こう側にあるデータの構造を見抜く。今回紹介した監査ロジックを自社のツールキットに組み込み、属人的な「印刷前の手動チェック」という非生産的な時間を排除してほしい。
コードは嘘をつかないが、設定は容易に人を裏切る。システムによって制約を課すことこそが、自由な創造への近道である。
