こんにちは! Visio VBAの世界へようこそ。
マクロの記録ボタンを押して、生成されたコードを眺めてみたものの、「これ、一体どういう仕組みになっているんだ?」と途方に暮れた経験はありませんか?
特に、サードパーティ製のステンシルや、誰が作ったのか分からない複雑なグループ図形を触っていると、「このシェイプ、一体裏側でどんな数式やデータを持っているんだ…?」と頭を抱えたくなりますよね。
今回は、そんなVisioのブラックボックスを丸裸にする、「ShapeSheetの全セクション動的走査テクニック」を伝授します。ここをクリアすれば、あなたは単なる「マクロの利用者」から、Visioのオブジェクトモデルを自在に操る「エンジニア」へと一歩踏み出すことができますよ。
それでは、Visio VBAの深淵へと一緒に出発しましょう!
—
1. そもそも「ShapeSheet」とオブジェクトモデルって何?
Visioのすべての図形(Shape)は、実はExcelのシートのような、行と列の巨大なデータベースを隠し持っています。これが「ShapeSheet(シェイプシート)」です。
位置(X, Y座標)、幅、高さ、色、そしてユーザー定義のカスタムプロパティに至るまで、Visioの図形に関する情報はすべてこのShapeSheetの中に「数式」として格納されています。
VBAでこれを操作するときの階層構造(オブジェクトモデル)は、およそ次のようになっています。
Application (Visio本体)
┗ Documents (図面ファイル)
┗ Pages (ページ)
┗ Shapes (図形)
┗ Sections (セクション:例=User-Defined Cells, Shape Dataなど)
┗ Rows (行)
┗ Cells (セル:個別の値や数式)
通常の開発では、「`Shape.CellsU(“Width”).Formula`」のように、見えているプロパティ名を名指ししてアクセスします。しかし、「中に何が入っているか分からない未知のシェイプ」を相手にする場合は、この名前指しが使えません。
だからこそ、すべてのセクション、すべての行、すべてのセルを全自動で巡回(走査)する仕組みが必要になるのです。
—
2. 【実践】未知の構造を暴く!全セクション走査プログラム
百聞は一見に如かず。選択しているシェイプのShapeSheetを隅々まで解剖し、イミディエイトウィンドウにその全貌を出力するVBAコードを書いてみましょう。
以下のコードを、VisioのVBAエディタ([Alt] + [F11])の標準モジュールに貼り付けてください。
Sub InspectSelectedShapeSheet()
‘ —————————————————————–
‘ チーフアーキテクト直伝:ShapeSheet全走査マクロ
‘ —————————————————————–
Dim vsoShape As Visio.Shape
Dim secIdx As Integer, rowIdx As Integer, cellIdx As Integer
Dim vsoSection As Visio.Section
Dim vsoRow As Visio.Row
Dim vsoCell As Visio.Cell
‘ 1. 選択チェック
If Visio.ActiveWindow.Selection.Count = 0 Then
MsgBox “解析したい図形を1つだけ選択してください。”, vbExclamation, “警告”
Exit Sub
End If
Set vsoShape = Visio.ActiveWindow.Selection(1)
‘ ヘッダー出力
Debug.Print “====================================================”
Debug.Print ” 解析開始: ” & vsoShape.Name & ” (ID: ” & vsoShape.ID & “)”
Debug.Print “====================================================”
‘ 2. セクションの走査 (Section)
‘ Visioではセクションが飛び飛びのインデックスを持つため、Countから逆順で安全に回すのが定石です
For secIdx = 1 To vsoShape.Count
Set vsoSection = vsoShape.Section(vsoShape.Section(secIdx).Index) ‘ ※安全なインデックス取得
Debug.Print “————————————————–”
Debug.Print ” [Section] インデックス: ” & vsoSection.Index
‘ 3. 行の走査 (Row)
If vsoSection.Count > 0 Then
For rowIdx = 0 To vsoSection.Count – 1
Set vsoRow = vsoSection.Row(rowIdx)
‘ 4. セルの走査 (Cell)
If vsoRow.Count > 0 Then
For cellIdx = 0 To vsoRow.Count – 1
Set vsoCell = vsoRow.Cell(cellIdx)
‘ 結果をイミディエイトウィンドウに出力
‘ NameU(ユニバーサル名) と Formula(数式) を取得するのがプロの技
Debug.Print ” -> Row[” & rowIdx & “] Cell[” & vsoCell.Name & “] = ” & vsoCell.Formula
Set vsoCell = Nothing
Next cellIdx
End If
Set vsoRow = Nothing
Next rowIdx
End If
Set vsoSection = Nothing
Next secIdx
Debug.Print “====================================================”
Debug.Print ” 解析完了!”
Debug.Print “====================================================”
MsgBox “解析が完了しました。イミディエイトウィンドウを確認してください。”, vbInformation, “完了”
End Sub
—
3. コードのキモと、初心者がハマりやすい「3つの罠」
上記のコードには、Visio VBAを極めた者だけが知る「現場の知見」がいくつも詰まっています。ここで重要なポイントを解説しておきましょう。
① セクションのインデックスは「連続しているとは限らない」
VisioのShapeSheetは、後から行やセクションが追加・削除されるため、内部のインデックスが飛び飛びになることがあります。通常の `For i = 1 To Count` で単純にアクセスすると、存在しないインデックスを叩いてエラー(実行時エラー)になる危険性があります。
コード内でオブジェクトの `.Index` プロパティを正しく経由しているのは、このメモリ上のズレを回避するための防御的プログラミングです。
② `.Formula` と `.ResultIU` の使い分け
今回のコードでは `vsoCell.Formula`(セルに入っている数式そのもの)を取得しています。
もし、計算された実際の数値(内部単位:インチなど)が欲しい場合は `vsoCell.ResultIU` を使いますが、「何という数式や他のセルへの参照が組まれているか」を暴くには `Formula` が最強です。隠しリンクや依存関係を見つけるには、数式をそのまま覗くのが一番の近道だからです。
③ オブジェクトの解放(`Set … = Nothing`)を怠らない
Visio VBAで最も恐ろしいのは、背後でCOMオブジェクトがメモリリークを起こし、Visioそのものがフリーズすることです。ループ内で生成した `Section`, `Row`, `Cell` などのオブジェクトは、使い終わったらこまめに `Nothing` を代入してメモリを解放してあげましょう。これができる人は、シニアエンジニアの仲間入りです。
—
4. まとめ:ここをクリアすればVisio VBAは怖くない!
今回紹介した「全セクションの動的走査」は、一見すると地味なデバッグ手法に思えるかもしれません。しかし、「オブジェクトの階層構造をコードで自由に行き来する」というスキルこそが、複雑なVisio自動化ツールを開発するための最大の武器になります。
「マクロの記録」の枠を飛び出し、自分自身の頭でオブジェクトモデルを縦横無尽に駆け巡らせる快感を、ぜひ味わってみてください。
ここをクリアしたあなたなら、どんなに複雑な図形データが相手でも、もう怖気づくことはありません。
それでは、次回の高度な自動化テクニックでお会いしましょう。お疲れ様でした!
