Visioエンジンを調教する:Page.Layoutによる自動再配置の極限最適化
Visioの自動レイアウト機能は、多くのエンジニアにとって「気まぐれなブラックボックス」だ。しかし、実務において数千のシェイプを接続した複雑なダイアグラムをハンドコーディングで座標指定するのはナンセンスである。
我々アーキテクトは、Visioの描画エンジンである「Layoutエンジン」をVBAから直接叩き、メモリを浪費させずに一瞬でフローを整列させる術を知らねばならない。本稿では、`Page.Layout`メソッドを核とした、実戦投入レベルの自動再配置アーキテクチャを伝授する。
—
1. なぜ「Page.Layout」は事故を起こすのか
`Page.Layout`を単に呼ぶだけでは、Visioは「ページ内の全シェイプ」に対して、デフォルトのアルゴリズムで再計算を試みる。これが数千個のシェイプを持つ巨大ドキュメントで発生すると、スタックオーバーフローやメモリの断片化、最悪の場合は描画エンジンがハングアップする。
必須の事前準備:オブジェクトの明示的解放
VBAにおいて、`Visio.Shape`や`Visio.Page`は、参照しているだけでメモリを食う。ループ内でシェイプを走査する際、オブジェクト変数を明示的に `Nothing` に戻さなければ、ガベージコレクションは期待できない。
—
2. 自動レイアウト実行の極意:実装コード
以下は、Pageオブジェクトを引数に取り、指定した方向にレイアウトを強制再計算させる堅牢なプロシージャである。
Option Explicit
‘ 自動レイアウトの定数定義
‘ visLOFlags… はレイアウトエンジンへの指示書である
Public Sub ExecuteSmartLayout(ByRef targetPage As Visio.Page, ByVal layoutDirection As Visio.VisLayoutDirection)
On Error GoTo ErrorHandler
‘ 1. パフォーマンス最適化:画面更新の停止
‘ APIを叩く前にこれをやらないエンジニアはプロ失格である
Application.ScreenUpdating = False
Dim layoutObj As Visio.Layout
Set layoutObj = targetPage.Layout
‘ 2. エンジンのパラメータ設定
‘ visLOTypeFlow: フロー図として認識させる
‘ visLOOrientation…: 進行方向の制御
With layoutObj
.LayoutDirection = layoutDirection
.EnableGrid = True
.LayoutType = visLOTypeFlow
End With
‘ 3. レイアウトの実行
‘ ここで再計算が走る
targetPage.Layout
GoTo Cleanup
ErrorHandler:
Debug.Print “Error: ” & Err.Description
Cleanup:
‘ 4. メモリ解放
Set layoutObj = Nothing
Application.ScreenUpdating = True
End Sub
コードの要点
- Application.ScreenUpdating: これを制御しないと、再計算プロセスがGUI描画と競合し、処理時間が10倍以上に跳ね上がる。
- Error Handling: Visioのレイアウトエンジンは、接続関係(コネクタ)が物理的に破綻しているとエラーを投げる。例外処理は必須だ。
—
3. レガシー環境でのAPI連携と安定化
大規模なシステム連携において、Visioファイルが外部DBから生成される場合、接続情報が不完全なまま`Page.Layout`を呼ぶと、シェイプがページ外へ吹き飛ぶことがある。
Windows APIによる「強制的な描画更新」の工夫
VBA単体では、レイアウト後の描画更新が同期的に完了しないことがある。その場合、以下のWindows APIを併用し、プロセスにメッセージを強制送信する手法が有効だ。
‘ User32.dllを介した再描画命令
If VBA7 Then
Private Declare PtrSafe Function RedrawWindow Lib “user32” (ByVal hwnd As LongPtr, ByVal lprcUpdate As LongPtr, ByVal hrgnUpdate As LongPtr, ByVal fuRedraw As Long) As Long
Else
Private Declare Function RedrawWindow Lib “user32” (ByVal hwnd As Long, ByVal lprcUpdate As Long, ByVal hrgnUpdate As Long, ByVal fuRedraw As Long) As Long
End If
レイアウト計算完了直後に `RedrawWindow` を呼ぶことで、Visio側の描画キューをフラッシュさせ、ユーザーに「整列後の姿」を瞬時に表示させることができる。
—
4. アーキテクトとしての助言:保守性の担保
「自動レイアウト」の最大の問題は、一度自動で整列させると、元のレイアウト情報が失われることだ。
1. スナップショットの保存: レイアウトを実行する直前に、`Document.SaveAs` でバックアップを自動生成するロジックを必ず組み込め。
2. コネクタの「型」: 自動レイアウトが機能するのは、正しく `Glue`(接着)されたコネクタのみだ。`Shape.Connects` プロパティを走査し、接続が切れているシェイプがあれば、ログを出力して「手動修正が必要なリスト」を生成するフィルタを実装せよ。
結論
Visioのレイアウトエンジンは、適切にパラメータを絞り込み、メモリ管理を徹底すれば、極めて強力な自動化武器になる。GUI上でポチポチとシェイプを動かす時間は、もう終わりだ。コードで配置を定義し、エンジンに計算を委ねる。これこそが、次世代の業務自動化エンジニアが持つべき作法である。
貴殿のシステムにおいて、このロジックが美しく機能することを確信している。
