【テクニカル・上級編】マウス操作はもう不要:VBAでコネクタ(線)を生成し2つの図形間を自動ルーティングする – Visio VBA解析バイブル

スポンサーリンク

マウス操作はもう不要:Visio VBAによる動的コネクタ生成とスマート・ルーティングの極意

配線図、ネットワーク構成図、あるいは複雑な業務フローチャート。数千のシェイプと、それらを幾重にも結ぶコネクタの海を、マウスのドラッグ&ドロップという前近代的な手法で構築していませんか?

シニアエンジニアやインフラストラクチャの自動化を担う者にとって、GUIによる手動描画は悪夢でしかない。レイアウト変更のたびに破綻する配線、意図しないルーティング、そして何より再現性の欠如。これらを根絶するのが、Visio VBA(Visual Basic for Applications)による完全プログラム制御だ。

今回は、マスターシェイプに依存せず、コードの奔流によってコネクタを生成し、起点と終点のシェイプを完璧に自動ルーティングするための極限の知見を授ける。

1. Visioオブジェクトモデルの深層:コネクタの本質を見極める

Visioにおける「コネクタ」は、単なる直線や折れ線ではない。それは「2つのシェイプの接着ポイント(Glue)を橋渡しする特殊なセマンティクスを持つオブジェクト」である。

多くの初学者が陥る罠は、`Page.DrawLine` などのメソッドで適当な座標に線を引き、それを無理やり図形に重ねようとすることだ。これは爆弾を抱えるようなものである。図形を移動させた瞬間にリンクが切れ、線は宙に浮く。

真に堅牢な自動配線を実現するためには、以下のプロセスを厳密に踏む必要がある。

1. コネクタシェイプの生成: `Page.Drop` または `Page.DrawLine` を用いたインスタンス化。
2. ピンの特定 (Cellの取得): 接続元・接続先の `PinX` / `PinY` ではなく、グルー可能な接続ポイント(Connection Points)またはシェイプの接着セルを特定する。
3. グルーイング (Glue): COMのセルレベルでの結合処理。

2. 実装:マスターレス動的コネクタ生成エンジン

以下のコードは、マスターシェイプ(ステンシル)を一切読み込まず、純粋なVBAのコードロジックのみで2つのシェイプを動的に生成し、それらを不可避的に接続・ルーティングする実用プロシージャである。

Option Explicit

‘ =========================================================================
‘ 処理名: 2つのシェイプをプログラムから生成し、スマートコネクタで自動配線する
‘ ターゲット: Visio 2010 / 2013 / 2016 / 2019 / M365
‘ =========================================================================
Public Sub CreateAndRouteSmartConnector()
Dim vsoPage As Visio.Page
Set vsoPage = ActivePage

‘ 画面描画の凍結(パフォーマンス最適化の極意)
‘ 描画イベントを抑制することで、数倍から数十倍の速度向上の恩恵を受ける
Application.ScreenUpdating = False

Dim vsoShape1 As Visio.Shape
Dim vsoShape2 As Visio.Shape
Dim vsoConnector As Visio.Shape

On Error GoTo ErrorHandler

‘ 1. 起点となるシェイプの生成(矩形)
Set vsoShape1 = vsoPage.DrawRectangle(1, 5, 2.5, 4)
vsoShape1.Text = “起点サーバ”

‘ 2. 終点となるシェイプの生成(矩形)
Set vsoShape2 = vsoPage.DrawRectangle(5, 2, 6.5, 1)
vsoShape2.Text = “DBサーバ”

‘ 3. 動的コネクタの生成
‘ 「Dynamic connector」マスターをドキュメントのステンシルから取得してドロップする
Dim vsoMaster As Visio.Master
Set vsoMaster = GetDynamicConnectorMaster(vsoPage.Document)

If vsoMaster Is Nothing Then
Err.Raise 9999, “ConnectorError”, “ダイナミックコネクタのマスターを取得できませんでした。”
End If

Set vsoConnector = vsoPage.Drop(vsoMaster, 0, 0)

‘ 4. コネクタの始点(BeginX)をシェイプ1にグルー
GlueShapes vsoConnector, “BeginX”, vsoShape1, visAuto

‘ 5. コネクタの終点(EndX)をシェイプ2にグルー
GlueShapes vsoConnector, “EndX”, vsoShape2, visAuto

‘ 6. ルーティングスタイルの強制適用(直角ルーティングなど)
‘ プレースホルダーのルーティングを「ルート・ダイレクト」または「スマート・ルート」に設定
Dim vsoCell As Visio.Cell
Set vsoCell = vsoConnector.CellsU(“ObjType”)
vsoCell.FormulaU = “2” ‘ 2: ダイナミックコネクタの挙動

Set vsoCell = vsoConnector.CellsU(“ConLineRouteExt”)
vsoCell.FormulaU = “1” ‘ 1: 直角ルーティング

‘ 終了処理
Application.ScreenUpdating = True
MsgBox “配線の自動生成とルーティングが完了しました。”, vbInformation, “自動化完了”
Exit Sub

ErrorHandler:
Application.ScreenUpdating = True
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “致命的エラー”

‘ メモリ最適化:オブジェクトの明示的解放
Set vsoConnector = Nothing
Set vsoShape1 = Nothing
Set vsoShape2 = Nothing
Set vsoMaster = Nothing
Set vsoPage = Nothing
End Sub

‘ =========================================================================
‘ 補助関数: ドキュメント内からダイナミックコネクタのマスターを安全に取得
‘ =========================================================================
Private Function GetDynamicConnectorMaster(vsoDoc As Visio.Document) As Visio.Master
Dim i As Long
For i = 1 To vsoDoc.Masters.Count
If vsoDoc.Masters(i).Type = visTypeMasterShape Then
‘ UIVersionやNameUで「Dynamic connector」を厳密に特定
If InStr(1, vsoDoc.Masters(i).NameU, “Dynamic connector”, vbTextCompare) > 0 Then
Set GetDynamicConnectorMaster = vsoDoc.Masters(i)
Exit Function
End If
End If
Next i

‘ 組み込みステンシル(Basic Objects等)からロードを試みるフォールバック
Dim vsoStencil As Visio.Document
On Error Resume Next
Set vsoStencil = Application.Documents.OpenEx(“CONNEC_U.VST”, visOpenRO & visOpenDocked)
If Not vsoStencil Is Nothing Then
For i = 1 To vsoStencil.Masters.Count
If InStr(1, vsoStencil.Masters(i).NameU, “Dynamic connector”, vbTextCompare) > 0 Then
Set GetDynamicConnectorMaster = vsoStencil.Masters(i)
Exit Function
End If
Next i
End If
On Error GoTo 0
End Function

‘ =========================================================================
‘ 補助プロシージャ: セル同士を精密にグルー(接着)する
‘ =========================================================================
Private Sub GlueShapes(vsoConnector As Visio.Shape, cellName As String, vsoTargetShape As Visio.Shape, glueType As Integer)
Dim vsoCellConn As Visio.Cell
Dim vsoCellTarget As Visio.Cell

Set vsoCellConn = vsoConnector.CellsU(cellName)

‘ ターゲットシェイプの中心、あるいは最適なコネクションポイントを指すGlue
‘ ここではシェイプのPinX/PinY(あるいはピンチ・センター)へ直接グルーする手法
Set vsoCellTarget = vsoTargetShape.CellsU(“PinX”)

‘ 物理的結合(GlueTo)の実行
vsoCellConn.GlueTo vsoCellTarget
End Sub

3. シニアアーキテクトが教える、パフォーマンスとメモリ管理の極意

大規模な図面(シェイプ数が数千を超える環境)において、上記コードをそのまま実行するとメモリリークや極端なパフォーマンス低下を招く。以下の3点を必ず遵守せよ。

① `Application.ScreenUpdating = False` の絶対的活用

Visioはオブジェクトが追加・変更されるたびに、UIの再描画と空間インデックスの再構築を行う。これを防ぐために、トランザクションの開始と同時に画面更新を止め、処理が終わるやいなや復元する。これだけで処理速度が文字通り桁違いになる。

② COMオブジェクトの明示的解放(NULL代入)

VBAのガベージコレクションは頼りにならない。特にVisioのShapeやCellオブジェクトは、参照カウントが残ったままプロシージャを抜けると、メモリ空間にゾンビオブジェクトが残留し、Visioのプロセスが肥大化・不安定化する。
コードの最後では必ず `Set vsoConnector = Nothing` のように、下位オブジェクトから順に明示的な解放を行え。

③ コネクションポイントの戦略的選択

上記のサンプルコードでは簡略化のために `PinX` に対して `GlueTo` を行っているが、実務の現場では、シェイプの周囲に配置された Connection Points(接続ポイント) のインデックス(例: `Constraints.X[0]` など)を指定してグルーすべきである。これにより、意図した方向から線が引き出される美しい配線図が担保される。

結び

マウスによる配線作業は、プログラマの仕事ではない。それは手作業に縛られた旧時代のアプローチだ。
今回解説した動的コネクタ生成とスマート・ルーティングのロジックをシステム基盤やExcel/DBからのインポートツールに組み込むことで、ドキュメント生成の完全自動化(Infrastructure as CodeのVisio版)が達成される。

コードを書き、システムを掌握せよ。自動化の限界は、あなたの設計図の解像度のみによって決まる。

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