Visio VBAを掌握する極限の知見:`Page.PrintProperties` を完全制御し、全図面の印刷設定を一撃で統制する
エンタープライズ規模のシステム設計図、あるいは数百ページに及ぶプラント配管図をVisioで管理していると、必ず直面する悪夢がある。
それが「複数ページにわたる印刷設定の不整合」だ。
あるページはA3横、別のページはA4縦、さらにあるページは「1ページに収める」設定が抜けていてPDF出力時に右側がプッツリ切れている――。これを人間の手で1枚ずつプロパティを開いて修正するなど、エンジニアの工数の無駄遣いであり、百害あって一利なしだ。
今回は、Visioのオブジェクトモデルの深層に切り込み、`Page.PrintProperties` を駆使して全ページの用紙サイズ・向き・印刷倍率(自動収まり)をプログラムから一括で強制統制する、プロダクション品質のVBAマクロを授与する。
—
1. なぜVisioの印刷設定制御はハマりやすいのか?
素人が書いたVisioマクロは、決まって次のようなコードで爆発する。
‘ 【アンチパターン】絶対にやってはいけない実装
Dim shp As Visio.Shape
For Each pg In ActiveDocument.Pages
pg.PageSheet.CellsSRC(visSectionObject, visRowPrintProperties, visPrintPropertiesPageSize).FormulaU = “7” ‘ A4のつもり
Next
なぜこれがダメなのか?理由は3つある。
1. マジックナンバーの恐怖: `7` が何を表すのか、半年後のあなたには読めない。Visioの用紙サイズ定数(`VisPaperSize`)を正しくマッピングしなければ、プリンタードライバーと喧嘩を始める。
2. 「自動ページ収まり(Fit to)」の排他制御: 「用紙幅・高さに合わせる」プロパティは、単にサイズを入れただけでは有効化されない。`PrintFitOnPages` や `PagesX`, `PagesY` のフラグを連動させて初めて機能する。
3. ドキュメントの重み(パフォーマンス): 画面描画(ScreenUpdating)を制御せずにページを走査すると、図面が点滅し、完了までに無駄な時間を奪われる。
プロのエンジニアであれば、トランザクション的な一括処理、定数の明示化、そして例外を許さない堅牢なエラーハンドリングを実装すべきだ。
—
2. 堅牢な設計:PrintProperties オブジェクトの構造
Visioの各ページ(`Page`)は、その裏側に必ずシェイプシート(`PageSheet`)を持っている。印刷プロパティ実体は、この `PageSheet` 内の `visSectionObject` > `visRowPrintProperties` セクションに格納されている。
これをVBAから安全に操作するため、以下の仕様を満たすプロシージャを設計する。
- 用紙サイズ: A4 (`visPaperA4`) または A3 (`visPaperA3`) を動的に指定可能。
- 向き: 縦 (`visPrnDevOrientationPortrait`) / 横 (`visPrnDevOrientationLandscape`)。
- 自動収まり: 「横○ページ、縦○ページに収める」の完全制御(例:1ページに収めるなら `PagesX = 1`, `PagesY = 1`)。
—
3. 【プロダクションコード】全ページ一括印刷設定統制ツール
以下のコードをVisioの標準モジュールに貼り付けてほしい。実務でそのまま使えるよう、画面描画の抑制やエラー対策、実行ログのイミディエイトウィンドウ出力まで完備している。
Option Explicit
‘ ==============================================================================
アクティブドキュメントの全ページの印刷プロパティ(サイズ・向き・収まり)を一括設定する
‘ ==============================================================================
Public Sub ApplyPrintPropertiesToAllPages()
‘ — 設定パラメータ(要件に合わせて変更してください) —
Const TARGET_PAPER_SIZE As Integer = visPaperA4 ; ‘ A4: visPaperA4, A3: visPaperA3
Const TARGET_ORIENTATION As Integer = visPrnDevOrientationLandscape ‘ 縦: visPrnDevOrientationPortrait, 横: visPrnDevOrientationLandscape
Const FIT_TO_PAGE_X As Integer = 1 ; ‘ 横方向に何ページ分に収めるか (0なら無効)
Const FIT_TO_PAGE_Y As Integer = 1 ; ‘ 縦方向に何ページ分に収めるか (0なら無効)
‘ ——————————————————–
Dim targetDoc As Visio.Document
Set targetDoc = ActiveDocument
‘ ドキュメントが開かれているか確認
If targetDoc Is Nothing Then
MsgBox “処理対象のドキュメントが開かれていません。”, vbCritical, “エラー”
Exit Sub
End If
‘ パフォーマンス劇的改善のための定石
Dim originalScreenUpdating As Boolean
originalScreenUpdating = Application.ScreenUpdating
Application.ScreenUpdating = False
Dim originalWaitCursor As Boolean
originalWaitCursor = Application.WaitCursor
Application.WaitCursor = True
On Error GoTo ErrorHandler
Dim pg As Visio.Page
Dim pageSheet As Visio.Shape
Dim processedCount As Long
processedCount = 0
Debug.Print “=== 印刷設定一括適用プロセス開始 ===”
For Each pg In targetDoc.Pages
‘ バックグラウンドページやマスターページを除外したい場合はここでガードを入れる
If Not pg.Background Then
Set pageSheet = pg.PageSheet
With pageSheet
‘ 1. 用紙サイズの指定
.CellsSRC(visSectionObject, visRowPrintProperties, visPrintPropertiesPageSize).FormulaU = TARGET_PAPER_SIZE
‘ 2. 印刷の向き(縦/横)の指定
.CellsSRC(visSectionObject, visRowPrintProperties, visPrintPropertiesPaperOrientation).FormulaU = TARGET_ORIENTATION
‘ 3. 自動ページ収まり(Fit to)の制御
If FIT_TO_PAGE_X > 0 Or FIT_TO_PAGE_Y > 0 Then
‘ ページに合わせるフラグを有効化 (True = 1)
.CellsSRC(visSectionObject, visRowPrintProperties, visPrintPropertiesFitFlags).FormulaU = 1
.CellsSRC(visSectionObject, visRowPrintProperties, visPrintPropertiesScaleMode).FormulaU = 2 ‘ 2: 拡大/縮小して合わせる
.CellsSRC(visSectionObject, visRowPrintProperties, visPrintPropertiesPagesX).FormulaU = FIT_TO_PAGE_X
.CellsSRC(visSectionObject, visRowPrintProperties, visPrintPropertiesPagesY).FormulaU = FIT_TO_PAGE_Y
Else
‘ 収まり設定を無効化する場合
.CellsSRC(visSectionObject, visRowPrintProperties, visPrintPropertiesFitFlags).FormulaU = 0
End If
End With
processedCount = processedCount + 1
Debug.Print “適用完了: ページ名 = ” & pg.Name
End If
Next pg
‘ 処理終了後のクリーンアップ
Application.ScreenUpdating = originalScreenUpdating
Application.WaitCursor = originalWaitCursor
Debug.Print “=== プロセス正常終了 (処理ページ数: ” & processedCount & “) ===”
MsgBox “全 ” & processedCount & ” ページの印刷設定を一括更新しました。”, vbInformation, “完了”
Exit Sub
ErrorHandler:
‘ 異常終了時も必ず画面描画フラグを復元する(これがないとVisioがフリーズしたような挙動になる)
Application.ScreenUpdating = originalScreenUpdating
Application.WaitCursor = originalWaitCursor
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error: ” & Err.Description, vbCritical, “致命的エラー”
Debug.Print “【エラー発生】 ” & Err.Description
End Sub
—
4. コードの急所:エンジニアが押さえるべき実装のポイント
① `Application.ScreenUpdating = False` の絶対死守
Visioは、ページオブジェクトのシェイプシート(`PageSheet`)を書き換えるたびに、UI上のプレビューやレイアウト再計算を走らせようとする。ページ数が50ページを超えたあたりから、この描画処理がボトルネックになり、マクロが異様なほど遅くなる。
コード例のように、処理の最初で画面描画を切り、最後に必ず復元する(エラー時も含む)のがプロの作法だ。
② `CellsSRC` とマジックナンバーのスマートな扱い
Visio VBAでは、セルへのアクセスに `CellsSRC`(Section, Row, Cell)を用いる。
印刷プロパティの行(`visRowPrintProperties`)には、用紙サイズ、向き、倍率、フィッティングフラグが密集している。
今回のコードでは、`VisPaperSize` などのVisio標準列挙体(Enums)を直接FormulaUに流し込んでいるため、プリンター依存のバグを未然に防ぐことができる。
③ バックグラウンドページの除外
Visioには「背景ページ(ヘッダーやフッター、方眼紙テンプレート等)」が存在する。これらに対しても無理やり印刷設定を適用すると、レイアウトの破損や不要なトラブルの元になる。`If Not pg.Background Then` というガード句によって、実体のある作図ページのみを安全にフィルタリングしている点に注目してほしい。
—
5. データベースや外部ファイル連携への発展性
このマクロをさらに実務で昇華させる場合、ハードコーディングされた `TARGET_PAPER_SIZE` を、Excel管理台帳や外部CSV、あるいはDBから動的に取得するアーキテクチャへと拡張することになる。
例えば、「図面管理DB」から図面IDごとのメタデータ(A3なのかA4なのか)を取得し、ループ内で `Select Case` を回して `TARGET_PAPER_SIZE` を切り替えるだけで、「社内ニッチな図面フォーマット自動コンバーター」の完成だ。
総括
Visio VBAにおけるオブジェクト操作は、背後にあるシェイプシートの構造とライフサイクルを理解していれば、恐るるに足りない。
今回提供した `Page.PrintProperties` 制御ロジックをあなたの開発環境に組み込み、煩雑な手作業地獄からチームを解放してほしい。エンジニアの本懐は、こうした機械的な苦作業をコードで駆逐することにあるのだから。
