Visio VBAの深淵:標準化されたドキュメントを「一瞬」で構築する極限の自動化設計
現場の自動化ツールを見ていて、いつも嘆かわしく思うことがある。それは、`ActivePage`に依存し、泥臭く`Add`を繰り返すコードだ。
Visioにおけるページ生成は、単なる「追加」ではない。それは「設計意図の継承」である。テンプレートから生成されるべきドキュメント構造を、場当たり的なマクロで汚染してはならない。
今日は、プロフェッショナルが現場で実装すべき、「ページの一括標準化生成ロジック」を伝授する。
—
1. なぜ「力技のAdd」が破滅を招くのか
多くの初心者は、ループ内で単に`Pages.Add`を実行する。だが、これには大きな落とし穴がある。
- ページインデックスの変動: 追加した瞬間にインデックスが変わるため、順序制御をミスると後続の処理で`Shape`の参照先が狂う。
- 背景ページの不整合: 自動生成時に明示的に背景を紐付けないと、印刷時にレイアウトが崩壊する。
- 名前の衝突: 同名ページが既に存在する場合、Visioは自動的にサフィックス(Page-1等)を付与する。これが「予期せぬ名前のページ」を生み、後続のDB連携やデータ転送を確実にクラッシュさせる。
—
2. 堅牢なページ生成:実戦的実装パターン
以下のコードは、単にページを作るのではない。「定義リスト」に基づき、構成を一括で確定させるためのプロトタイプだ。
Option Explicit
‘ ページ定義を格納する構造体
Private Type PageConfig
Name As String
Orientation As VisPageOrientation
BackgroundName As String
End Type
Public Sub GenerateStandardDocument()
Dim doc As Visio.Document
Dim pg As Visio.Page
Dim configs(1 To 3) As PageConfig
Dim i As Integer
Set doc = ThisDocument
‘ 生成仕様の定義(本来は外部CSVやJSONから読み込むのが筋だ)
configs(1) = DefinePage(“表紙”, visVisOrientationPortrait, “”)
configs(2) = DefinePage(“構成図”, visVisOrientationLandscape, “背景A”)
configs(3) = DefinePage(“詳細リスト”, visVisOrientationPortrait, “背景A”)
On Error GoTo ErrorHandler
For i = LBound(configs) To UBound(configs)
‘ 既存ページの有無を確認して制御する設計が鉄則
Set pg = GetOrAddPage(doc, configs(i))
‘ ページプロパティの強制適用
pg.PageSheet.Cells(“PageOrientation”).ResultIU = configs(i).Orientation
‘ 背景ページの設定(存在する場合のみ割り当て)
If configs(i).BackgroundName <> “” Then
pg.BackPage = doc.Pages(configs(i).BackgroundName)
End If
Next i
MsgBox “ドキュメント構造の標準化が完了しました。”, vbInformation
Exit Sub
ErrorHandler:
MsgBox “エラー発生: ” & Err.Description, vbCritical
End Sub
‘ ページ生成の抽象化層
Private Function GetOrAddPage(doc As Visio.Document, conf As PageConfig) As Visio.Page
On Error Resume Next
Set GetOrAddPage = doc.Pages(conf.Name)
If GetOrAddPage Is Nothing Then
Set GetOrAddPage = doc.Pages.Add
GetOrAddPage.Name = conf.Name
End If
End Function
Private Function DefinePage(name As String, ori As VisPageOrientation, bg As String) As PageConfig
DefinePage.Name = name
DefinePage.Orientation = ori
DefinePage.BackgroundName = bg
End Function
—
3. アーキテクトの視点:なぜこの設計なのか
A. 抽象化による保守性
`GetOrAddPage`関数を見てほしい。生成のロジックと、ビジネスロジック(どのページを作るか)を分離している。将来的に「ページ名に日付を付与したい」といった要件変更が発生しても、修正箇所は一箇所で済む。
B. ページシートへの直接アクセス
`Page.PageSheet.Cells(“PageOrientation”)` を直接操作している点に注目してほしい。VisioのプロパティをUIのメニューから探すのは時間の無駄だ。ShapeSheetのセル位置を特定し、数値を直接流し込む。これがVisio VBAにおける「最速にして最も確実な」操作だ。
C. 外部データとの連携における注意点
もし君たちが、データベース(SQL ServerやExcel)から取得した情報をもとにページを生成するなら、以下の鉄則を忘れてはならない。
1. 名前のサニタイズ: DBから取得した文字列には、Visioのページ名として使用不可能な文字が含まれている可能性がある。必ず正規表現等でフィルタリングすること。
2. トランザクション管理: ページ生成中にエラーが起きた場合、中途半端にページが残る。`On Error`でキャッチしたら、作成中のドキュメントをロールバック(あるいは生成済みページの削除)するクリーンアップルーチンを必ず実装せよ。
—
結論:ツールは「運用」までを見据えろ
自動化ツールは「動けば良い」ものではない。そのツールが、開発者以外の人間にも使い続けられ、将来の仕様変更にも耐えうるか。そこまで考えて初めて、それは「資産」となる。
Visioのオブジェクトモデルは、最初は複雑に見えるかもしれない。だが、`Application` → `Document` → `Page` → `Shape` という階層構造の本質さえ掴めば、もはや恐れるものはない。
さあ、泥臭い手作業を駆逐し、標準化された美しいドキュメントを量産するエンジニアリングの世界へようこそ。質問があればいつでも受け付ける。ただし、安易なコピペで済ませず、コードの背後にある意図を読み取ることだ。
