Visio VBAを掌握せよ:カオスな図形を数学的に制圧する「自動整列エンジン」の極意
業務自動化の現場で、Visioの図面を整理するためにマウスでドラッグ&ドロップを繰り返している者はいないだろうか? もしそうなら、今すぐその手を止めろ。それはエンジニアの仕事ではない。
Visioのオブジェクトモデルを正しく理解し、数学的な「座標計算」をVBAで記述すれば、どんなに複雑なレイアウトも一瞬で美しく整列させることができる。今回は、Visio VBAにおいて「なぜPinX/PinYの操作が失敗するのか」という核心に触れつつ、プロダクション環境で耐えうる堅牢な整列アルゴリズムを伝授する。
—
1. Visioの座標系を支配する:PinX/PinYの正体
多くの初心者が陥る罠がある。それは「Shapeを動かせば座標が変わる」という直感的な理解だけでコードを書くことだ。
VisioのShapeにおいて、`PinX`と`PinY`は「回転の中心点(Pin)」を示す。重要なのは、この値が「ページ上のどこにあるか」を指している点だ。シェイプの幅(Width)や高さ(Height)は中心点からの相対的な位置関係に過ぎない。
堅牢な設計のための3つの鉄則
1. Selectionを活用せよ: 画面上で選択されたオブジェクトをループ処理する際、`ActiveWindow.Selection`を用いるのが最も効率的だ。
2. 座標計算はメモリ上で完結させよ: ループ内で何度もShapeにアクセスして値を書き込むのはオーバーヘッドが大きい。必要ならば配列に一度格納し、計算後に一括適用する。
3. Lock系プロパティを考慮せよ: 保護されたシェイプに対して座標変更を強制するとエラーを吐く。`Cell.Locked`のチェックは必須だ。
—
2. 実践:グリッド整列アルゴリズム
以下は、選択されたシェイプを「指定した列数」でグリッド状に自動整列させるためのプロダクションコードだ。
Option Explicit
”’
”’
Public Sub AlignShapesInGrid()
Const COL_COUNT As Integer = 4 ‘ 横に並べる数
Const MARGIN_X As Double = 1.0 ‘ 横の間隔(インチ単位)
Const MARGIN_Y As Double = 1.0 ‘ 縦の間隔
Dim sel As Visio.Selection
Set sel = ActiveWindow.Selection
If sel.Count = 0 Then
MsgBox “整列対象の図形を選択してください。”, vbExclamation
Exit Sub
End If
Dim i As Long
Dim x As Double, y As Double
Dim startX As Double, startY As Double
‘ 最初の図形を基準点とする(必要に応じて固定座標へ変更可能)
startX = sel(1).Cells(“PinX”).ResultIU
startY = sel(1).Cells(“PinY”).ResultIU
Dim shp As Visio.Shape
For i = 1 To sel.Count
Set shp = sel(i)
‘ 計算ロジック:列と行を算出
Dim col As Integer, row As Integer
col = (i – 1) Mod COL_COUNT
row = (i – 1) \ COL_COUNT
‘ PinX/PinYを計算して代入
‘ .CellsU(“PinX”) を使用することでローカライズによるバグを回避
shp.CellsU(“PinX”).ResultIU = startX + (col MARGIN_X)
shp.CellsU(“PinY”).ResultIU = startY – (row MARGIN_Y)
Next i
Debug.Print “整列完了: ” & sel.Count & ” 個のシェイプを処理しました。”
End Sub
—
3. なぜこのコードが「現場」で生き残るのか
このコードには、ただ動くだけのスクリプトにはない「プロの設計思想」が3点含まれている。
① `.CellsU` の使用
`Cells`ではなく`CellsU`(Universal)を使っていることに注目してほしい。`Cells`は実行環境の言語設定に依存するが、`CellsU`はユニバーサルな名前(PinX, PinY等)を直接指定できる。これにより、英語環境・日本語環境のどちらでもバグを発生させない。
② `ResultIU`(Internal Units)の活用
Visioは内部的に「インチ」で計算を行う。ユーザーが設定で「ミリメートル」にしていても、`ResultIU`プロパティを使えば常に内部単位で計算できるため、単位変換による誤差やトラブルを完全に遮断できる。
③ データベース・ファイル連携時の注意点
もし外部CSVやDBから座標情報を読み込んで整列させる場合、「トランザクション」の意識を持つこと。
`Application.BeginUndoScope` を使用すれば、自動整列処理を「一つの操作」としてUndo(取り消し)可能にできる。これを怠ると、ユーザーは「整列したけど元に戻せない」という最悪のUXに直面する。
—
4. チーフアーキテクトからの助言
自動化のツールを作る際、最も危険なのは「自分のマシンで動いたからOK」という慢心だ。
Visioの図形はグループ化されていたり、コネクタで繋がっていたりする。今回紹介したコードは、「コネクタの追従」まで考慮していない。より複雑なフローチャートを扱う場合は、`Shape.Connects`オブジェクトを解析し、接続先を維持したまま座標をシフトさせる高度な再帰処理が必要になる。
だが、まずはこの基本を完璧にマスターせよ。グリッド整列一つをロジカルに書けるようになることが、複雑な業務自動化を達成するための第一歩だ。
コードをコピペして終わりにするな。その行がなぜ必要か、Visioのオブジェクトモデルがどう反応しているかを想像しながらデバッグし、自分自身のエンジンとして組み上げてほしい。健闘を祈る。
