こんにちは!Visio VBAの自動化の世界へようこそ。
マクロの記録ボタンを押してコードを覗いてみたものの、「なんだか生成された図形の名前が毎回バラバラになる」「図形を消したり作ったりしているうちに、プログラムが意図しない図形を掴んでエラーを起こす……」そんな壁にぶ和れていませんか?
「図形を自動で綺麗に並べたい」「データを流し込んで大量のフローチャートを作りたい」と思ったとき、必ずと言っていいほど直面するのが『図形の名前(Name / NameID)の衝突と追跡のトラブル』です。
今回は、数々のVisio自動化システムを構築してきたシニアエンジニアの視点から、動的に生成・削除される図形を完全にコントロールし、名前の衝突を華麗にかわす「ユニーク名管理術」の極意を優しく、そして深く伝授します。
ここをクリアすれば、あなたのVisio VBAのスキルは「初心者」から確実に脱却できますよ!バッチリついてきてくださいね。
—
1. なぜVisioの図形名(NameID)でハマるのか?
まずは、Visioが裏側でどうやって図形を管理しているかを知る必要があります。ここがすべての落とし穴のスタート地点です。
「名前」の3つの顔を理解する
Visioの `Shape` オブジェクトには、主に3つの名前に関連するプロパティがあります。
1. `Name`: ユーザーインターフェース(画面左側の図形ウインドウなど)で見える名前(例: `プロセス`, `プロセス.3` など)。
2. `NameID`: プログラムから図形を一意に識別するための、Visio内部の文字列(例: `Sheet.1!Basic_Shapes:id:1` や、単に `Sheet.1`)。
3. `Text`: 図形の中に書き込まれている文字列。
私たちがVBAで「図形を生成・指定」するときによく使うのは `Name` や `NameID` ですが、ここに大きな罠があります。
罠の正体:デフォルト名前付与ルールの恐怖
Visioは、図形をドロップ(生成)するたびに、同じマスターシェイプであれば自動的にインクリメント(連番)する名前を付けます。
- 1個目:`プロセス`
- 2個目:`プロセス.1`
- 3個目:`プロセス.2`
ここで恐ろしいのが、「途中で2個目の『プロセス.1』を削除したあとに、新しく図形を作るとどうなるか?」という点です。
Visioは空いた番号を再利用したり、ユニーク性を保とうと独自の採番を行うため、プログラム側で「さっき作ったあの図形をもう一度操作したい!」と思ったときに、名前が変わってしまったり、別の図形を指してしまったりするのです。これが名前の衝突と追跡ロストの正体です。
—
2. 解決策:Visioの「Master名」と「User セル」を活用したユニーク名管理
この混沌を制するためには、Visio任せの名前管理を卒業し、「自分で一意のID(キー)を図形に埋め込み、それを元にプログラムから探し出す」というアプローチを取ります。
プロの現場で使われている最も堅牢な手法は、図形のShapeSheet(内部プロパティ)の「User-defined Cells(ユーザー定義セル)」に独自のIDを書き込む方法です。
これなら、画面上の名前(`Name`)がどう変わろうとも、プログラム側からは「私のつけた固有IDを持つ図形はどれだ?」と確実に見つけ出すことができます。
—
3. 実践!動的生成と確実な追跡を行うVBAコード
百聞は一見にしかず。実際に「動的に図形を生成し、ユニークIDを付与し、後からそれを確実に呼び出して色を変える」という一連の処理を書いてみましょう。
以下のコードを、VisioのVBAエディタ(Alt + F11)の標準モジュールに貼り付けて実行してみてください。
Sub Demo_UniqueShapeManagement()
Dim vsoPage As Visio.Page
Set vsoPage = ActivePage
‘ 1. テスト用に新しい図形を動的に3つ生成し、ユニークIDを埋め込む
Dim i As Long
Dim targetID As String
targetID = “MyNode_B” ‘ 後から追跡したい特定のID
For i = 1 To 3
‘ 基本的な四角形(Rectangle)のマスターを取得してドロップ
Dim vsoMaster As Visio.Master
Set vsoMaster = Visio.Documents.Item(“basic_u.vssx”).Masters.ItemBypyName(“Rectangle”) ‘ ※環境に合わせてマスタ名は調整してください
‘ ※簡略化のため、今回はActivePageに単純な矩形を描画する例にします
Dim vsoShape As Visio.Shape
‘ 簡易的に長方形をドロップ(位置はX, Yで指定)
Set vsoShape = vsoPage.DrawRectangle(i 1, 5, i 1 + 1.5, 4)
‘ 【重要】独自のユニークIDを組み立てる
Dim uniqueKey As String
uniqueKey = “Node_” & i
‘ 図形にカスタムプロパティ(Userセルの行)を追加してユニークIDを書き込む
‘ これによりVisioの標準「Name」に依存しない絶対的な追跡が可能になります
Call SetCustomID(vsoShape, uniqueKey)
‘ ついでに見分けがつくようにテキストを入れる
vsoShape.Text = “ID: ” & uniqueKey
Debug.Print “生成完了: ” & uniqueKey & ” (Visio内部名: ” & vsoShape.Name & “)”
Next i
‘ 2. (ここで図形が削除されたり、順番が入れ替わったりしたと仮定)
‘ Visioの名前はあてにならないが、私たちが埋め込んだIDから「特定の図形」をピンポイントで探す!
MsgBox “図形を生成しました。これからユニークID ‘Node_B’ を持つ図形を探して赤色に変えます。”, vbInformation, “実演”
Dim foundShape As Visio.Shape
Set foundShape = FindShapeByCustomID(vsoPage, “Node_2”) ‘ Node_2 を探す
If Not foundShape Is Nothing Then
‘ 見つかった!色を赤に変更する(CellsSRCで塗りつぶし色を変更)
foundShape.CellsSRC(visSectionObject, visRowFill, visFillForegnd).ResultIU = RGB(255, 0, 0)
MsgBox “お見事! ‘Node_2’(Visio名が変わっていてもOK)を特定し、赤色に変更しました。”, vbInformation, “成功”
Else
MsgBox “指定されたIDの図形が見つかりませんでした。”, vbCritical, “エラー”
End If
End Sub
‘ ==========================================
‘ 補助関数1: 図形にカスタムのユニークID(Userセル)を刻み込む
‘ ==========================================
Private Sub SetCustomID(vsoShape As Visio.Shape, idString As String)
Const propName As String = “MyUniqueKey”
‘ すでにUserセクションに同名の行がないか確認し、なければ追加
If Not vsoShape.CellExistsU(“User.” & propName, visExistsLocally) Then
vsoShape.AddNamedRow visSectionUser, propName, visTagDefault
End If
‘ 値としてユニーク文字列を格納(シングルクォーテーションで囲む)
vsoShape.CellsU(“User.” & propName).FormulaU = “””” & idString & “”””
End Sub
‘ ==========================================
‘ 補助関数2: ページ内を走査し、カスタムIDが一致する図形を返す(追跡の決定版)
‘ ==========================================
Private Function FindShapeByCustomID(vsoPage As Visio.Page, targetID As String) As Visio.Shape
Const propName As String = “MyUniqueKey”
Dim shp As Visio.Shape
For Each shp in vsoPage.Shapes
‘ ユーザー定義セルが存在し、かつ値が一致するかチェック
If shp.CellExistsU(“User.” & propName, visExistsLocally) Then
‘ CellsUの値を取得(前後につくダブルクォーテーションを取り除く)
Dim currentID As String
currentID = shp.CellsU(“User.” & propName).ResultStr(“”)
If currentID = targetID Then
Set FindShapeByCustomID = shp
Exit Function
End If
End If
Next shp
‘ 見つからなければNothingを返す
Set FindShapeByCustomID = Nothing
End Function
—
4. コードの解説と「エンジニアの知見」
このコードの肝は、Visioが自動的につける `Name` や `NameID` を一切信用しないという点にあります。
なぜ `CellsSRC` や `User` セルを使うのか?
Visioの図形は、Excelでいうセルのような数式構造(ShapeSheet)を持っています。その中に `User` という、ユーザーが自由に使えるカスタム領域(変数置き場のようなもの)が存在します。
ここに `MyUniqueKey` という名前の行を作り、プログラム側で決めたID(例: `Node_2`)を書き込んでおきます。
こうすることで、ユーザーが画面上で図形を移動させようが、別の図形を間に挟んで自動採番名が変わろうが、図形が持つ「戸籍(Userセルの値)」は一生変わりません。
検索する際も、ページ内の全図形(`vsoPage.Shapes`)をループさせて、「私の戸籍IDはこれですか?」と1つずつ確認していくため、名前の衝突による誤作動を100%防ぐことができます。
—
まとめ:名前衝突の恐怖から解放されるために
今回は、Visio VBAにおける図形名の衝突を防ぎ、確実に図形を追跡するユニーク名管理術を解説しました。
- Visioのデフォルト名(`Name` / `NameID`)は自動で変わるため、プログラムのキーとして使ってはならない。
- 図形のShapeSheet(Userセル)に独自のIDを書き込み、それを「戸籍」として利用する。
- 検索時はページ内の図形をループし、Userセルの値でマッチングを行う。
このテクニックを身につければ、数千個の図形を動的に生成・削除・更新するような大規模な自動化ツールを作っても、エラーに怯えることはもうなくなります。
「ここをクリアすれば、Visio VBAの基本はバッチリですよ!」
ぜひ次の開発案件や業務効率化のマクロに、この設計を取り入れてみてください。あなたのVBAライフが、より堅牢でスマートなものになることを応援しています!
