【入門編】【中級】複数のステンシルからシェイプを検索・一括配置する自動化ツール – Visio VBA解析バイブル

スポンサーリンク

Visio VBAマスターへの道:複数のステンシルからシェイプを検索・一括配置する自動化ツールを徹底解説!

皆さん、こんにちは!Visio VBAの世界へようこそ。前回はVisio VBAの基礎の基礎、マクロの記録から一歩進んだオブジェクト操作の基本についてお話ししました。今回は、その応用編として、複数のステンシルを自在に操り、目的のシェイプを効率的に探し出してページに配置する、そんな実務で役立つ自動化ツールの作成に挑戦しましょう!

「え、複数のステンシルからシェイプを探すなんて、手作業でも大変なのに…」と思ったあなた、ご安心ください。Visio VBAを使えば、この作業は驚くほど簡単に、そして自動化できるんです。このブログ記事を読み終える頃には、あなたもVisio VBAを使いこなして、作業効率を劇的に向上させる魔法使いになっているはずですよ!

なぜ「複数のステンシルからシェイプを検索・一括配置」が重要なのか?

業務でVisioを使う場面を想像してみてください。

  • 複雑なシステム構成図: サーバー、ネットワーク機器、アプリケーションなど、様々な要素を表現するために、複数のベンダーや用途のステンシルを利用している。
  • 標準化された図面作成: 会社や部署で定められた標準シェイプがあり、それらを組み合わせて図面を作成する。
  • 頻繁な図面更新: 新しい機器の追加や構成変更に伴い、既存の図面を更新する必要がある。

このような状況で、目的のシェイプを探すために一つずつステンシルを開いていくのは、時間と労力の無駄ですよね。そこで、VBAの出番です!あらかじめ登録しておいた複数のステンシルから、名前でシェイプを検索し、指定した場所に一括で配置できれば、どれだけ作業が楽になることか!

この自動化ツールをマスターすれば、

  • 図面作成時間の短縮
  • ミスの軽減(シェイプの選択間違いなど)
  • 標準化された図面の作成促進

といった、数々のメリットを享受できます。さあ、Visio VBAの真髄に触れる旅へ、出発しましょう!

1. 複雑なVisioオブジェクトモデルを紐解く:ステンシルとマスターシェイプの「ライフサイクル」

VBAで何かを操作する前に、その対象がVisioの中でどのように存在しているのか、その「ライフサイクル」を理解することが極めて重要です。特に、ステンシルとマスターシェイプの関係は、この自動化ツールの肝となります。

# 1.1. ステンシル(Stencil)とは?

ステンシルは、Visioの図面で利用できるシェイプの「テンプレート集」のようなものです。通常、Visioを起動すると、左側の「図形」ウィンドウに表示されるシェイプのまとまりがステンシルです。

  • ファイル形式: `.vss` (古い形式) または `.vssx` (新しい形式)
  • 役割: マスターシェイプを管理し、ドラッグ&ドロップで図形ウィンドウに配置できるようにする。

# 1.2. マスターシェイプ(MasterShape)とは?

マスターシェイプは、ステンシルに含まれる個々のシェイプの「元」となるデータです。このマスターシェイプをページにドラッグ&ドロップすることで、実際の図形(Shape)が生成されます。

  • 位置づけ: ステンシルという「箱」の中に格納されている、個々の「実体」
  • 属性: 名前、サイズ、形状、接続点、データなど、図形が持つべき情報が定義されている。

# 1.3. オブジェクトモデルでの位置づけ

VBAでこれらの要素にアクセスするには、Visioのオブジェクトモデルを理解する必要があります。

  • `Application` オブジェクト: Visioアプリケーション全体を表します。
  • `Documents` コレクション: 開いているすべてのVisioドキュメント(`.vsd` ファイルなど)を表します。
  • `Document` オブジェクト: 特定のVisioドキュメントを表します。
  • `Masters` コレクション: ドキュメントに読み込まれている(またはドキュメント自体が持つ)マスターシェイプのコレクションです。
  • `Master` オブジェクト: 個々のマスターシェイプを表します。
  • `Stencils` コレクション: ドキュメントに読み込まれているステンシル(`.vss` または `.vssx` ファイル)のコレクションです。
  • `Stencil` オブジェクト: 個々のステンシルを表します。

ここが重要!
通常、私たちが「ステンシルを開く」という操作をすると、そのステンシルファイル(`.vss`/`.vssx`)はVisioの「開いているドキュメント」として扱われ、その中身であるマスターシェイプにアクセスできるようになります。しかし、VBAでプログラムから「ステンシルを読み込む」場合、`Application.Documents.Add(“ステンシルファイル名.vssx”)` のようにして、ステンシルファイルを「ドキュメント」として開くのではなく、`Application.Stencils` コレクションに直接追加する方が、より管理しやすく、後々の処理もスムーズになります。

後述するコード例では、この `Application.Stencils.Add` メソッドを活用します。

2. 自動化ツールの設計:何を実現したいか?

今回の自動化ツールで実現したいことは、以下の3点です。

1. 複数のステンシルをリスト化し、プログラムで開く(読み込む)。
2. 開いた(読み込んだ)ステンシルの中から、指定した名前のマスターシェイプを検索する。
3. 見つかったマスターシェイプを、指定したページ上の座標に配置する。

この3つのステップを、VBAコードで実現していきます。

3. 実践!Visio VBAコードで自動化ツールを作成しよう

それでは、いよいよコードを書いていきましょう。
まずは、このツールを起動するための「トリガー」となるVBAプロシージャ(Subプロシージャ)を作成します。

# 3.1. 基本的なSubプロシージャの作成

'----------------------------------------------------------------------------------------
' プロシージャ名: BatchPlaceShapesFromStencils
' 概要: 複数の指定されたステンシルから、指定されたシェイプを検索し、
'       アクティブなページに指定座標で一括配置する。
' 使い方: このプロシージャを実行すると、シェイプの配置が開始される。
'----------------------------------------------------------------------------------------
Sub BatchPlaceShapesFromStencils()

    ' --- 設定項目 ---
    ' 配置したいシェイプの名前(大文字・小文字を区別しない検索とするため、後で小文字に変換する)
    Const TARGET_SHAPE_NAME_TO_FIND As String = "サーバー" ' 例: "サーバー"、"ルーター" など

    ' 検索対象とするステンシルファイルのパスとファイル名の配列
    ' ※実際の環境に合わせて、パスとファイル名を正確に指定してください。
    Dim stencilPaths() As Variant
    stencilPaths = Array( _
        "C:\Users\YourUser\Documents\Visio\Custom Stencils\Network_Devices.vssx", _
        "C:\Users\YourUser\Documents\Visio\Custom Stencils\Servers.vssx", _
        "C:\Program Files\Microsoft Office\root\Visio Content\1041\Networking Basic Shapes.vssx" _
    )

    ' 配置先のページオブジェクト(アクティブなページを取得)
    Dim targetPage As Visio.Page
    Set targetPage = Visio.ActivePage

    ' 配置したいシェイプの配置座標 (X, Y)
    ' ※Visioの座標系は、通常、ページの中央が (0, 0) となります。
    '   単位はVisioの内部単位(インチなど)ですが、ここでは相対的な位置として指定します。
    '   例: (2, 4) は、ページの中央から右へ2単位、上へ4単位の位置
    Dim targetX As Double
    Dim targetY As Double
    targetX = 2.0
    targetY = 4.0

    ' --- 処理本体 ---
    Dim foundMasterShape As Visio.Master
    Dim placedShape As Visio.Shape
    Dim errorMessage As String
    Dim foundFlag As Boolean
    Dim i As Integer
    Dim j As Integer

    ' エラーハンドリングの初期化
    errorMessage = ""
    foundFlag = False

    ' 検索対象のシェイプ名を小文字に変換(大文字・小文字を区別しない検索のため)
    Dim lowerTargetShapeName As String
    lowerTargetShapeName = LCase(TARGET_SHAPE_NAME_TO_FIND)

    ' 1. 指定されたステンシルをループ処理で開く(読み込む)
    Debug.Print "--- ステンシルの読み込み開始 ---"
    For i = LBound(stencilPaths) To UBound(stencilPaths)
        Dim currentStencilPath As String
        currentStencilPath = stencilPaths(i)

        ' ステンシルファイルが存在するかチェック
        If Dir(currentStencilPath) = "" Then
            errorMessage = errorMessage & "エラー: ステンシルファイルが見つかりません - " & currentStencilPath & vbCrLf
            Debug.Print "警告: ステンシルファイルが見つかりません - " & currentStencilPath
            GoTo NextStencil ' 次のステンシルへ
        End If

        'ステンシルが既に開かれているかチェック
        Dim existingStencil As Visio.Stencil
        Dim isAlreadyOpen As Boolean
        isAlreadyOpen = False
        For Each existingStencil In Visio.Stencils
            'ステンシルのURI(Uniform Resource Identifier)で比較すると正確
            If LCase(existingStencil.URI) = LCase("file://" & currentStencilPath) Then
                isAlreadyOpen = True
                Debug.Print "情報: ステンシルは既に開かれています - " & currentStencilPath
                Exit For
            End If
        Next existingStencil

        ' まだ開かれていない場合のみ、ステンシルを読み込む
        If Not isAlreadyOpen Then
            On Error Resume Next ' エラーが発生しても処理を続行
            Dim addedStencil As Visio.Stencil
            Set addedStencil = Visio.Stencils.Add(currentStencilPath)
            If Err.Number <> 0 Then
                errorMessage = errorMessage & "エラー: ステンシルの読み込みに失敗しました - " & currentStencilPath & " (エラーコード: " & Err.Number & ")" & vbCrLf
                Debug.Print "エラー: ステンシルの読み込みに失敗しました - " & currentStencilPath & " (エラーコード: " & Err.Number & ")"
                Err.Clear
            Else
                Debug.Print "成功: ステンシルを読み込みました - " & currentStencilPath
            End If
            On Error GoTo 0 ' 通常のエラーハンドリングに戻す
        End If
NextStencil:
    Next i
    Debug.Print "--- ステンシルの読み込み完了 ---"

    ' 2. 読み込んだステンシルの中から、目的のマスターシェイプを検索する
    Debug.Print "--- マスターシェイプの検索開始 ('" & TARGET_SHAPE_NAME_TO_FIND & "') ---"
    For Each foundMasterShape In Visio.Masters
        ' マスターシェイプの名前を小文字に変換して比較
        If LCase(foundMasterShape.Name) = lowerTargetShapeName Then
            foundFlag = True
            Debug.Print "発見: マスターシェイプ '" & foundMasterShape.Name & "' を見つけました。"
            Exit For ' 見つかったらループを抜ける
        End If
    Next foundMasterShape
    Debug.Print "--- マスターシェイプの検索完了 ---"

    ' 3. 見つかったマスターシェイプを指定座標に配置する
    If foundFlag Then
        Debug.Print "--- シェイプの配置開始 ---"
        On Error Resume Next ' 配置時のエラーを無視(例: ページが無効など)
        Set placedShape = targetPage.Drop(foundMasterShape, targetX, targetY)

        If Err.Number <> 0 Then
            errorMessage = errorMessage & "エラー: マスターシェイプ '" & foundMasterShape.Name & "' の配置に失敗しました。 (エラーコード: " & Err.Number & ")" & vbCrLf
            Debug.Print "エラー: マスターシェイプ '" & foundMasterShape.Name & "' の配置に失敗しました。 (エラーコード: " & Err.Number & ")"
            Err.Clear
        Else
            Debug.Print "成功: マスターシェイプ '" & foundMasterShape.Name & "' を (" & targetX & ", " & targetY & ") に配置しました。"
            ' 配置後のシェイプに対する追加処理があれば、ここで行う
            ' 例: シェイプのテキストを変更する
            ' placedShape.Text = "配置された " & foundMasterShape.Name
        End If
        On Error GoTo 0 ' 通常のエラーハンドリングに戻す
        Debug.Print "--- シェイプの配置完了 ---"
    Else
        errorMessage = errorMessage & "情報: 指定されたマスターシェイプ '" & TARGET_SHAPE_NAME_TO_FIND & "' は、開かれたステンシルの中に見つかりませんでした。" & vbCrLf
        Debug.Print "情報: 指定されたマスターシェイプ '" & TARGET_SHAPE_NAME_TO_FIND & "' は、開かれたステンシルの中に見つかりませんでした。"
    End If

    ' --- 結果の表示 ---
    If errorMessage <> "" Then
        MsgBox "処理中に以下の問題が発生しました:" & vbCrLf & errorMessage, vbExclamation, "シェイプ配置ツール - 結果"
    Else
        MsgBox "指定されたシェイプの配置が完了しました。", vbInformation, "シェイプ配置ツール - 完了"
    End If

    ' 後処理: 開いたステンシルを閉じるかどうか?
    ' 毎回閉じる場合は、以下のコードをコメント解除してください。
    ' ただし、大量のステンシルを閉じるのはパフォーマンスに影響する可能性があるので注意が必要です。
    ' If Not isAlreadyOpen Then ' 自分で開いたステンシルのみ閉じる場合
    '     On Error Resume Next
    '     addedStencil.Close
    '     On Error GoTo 0
    ' End If

End Sub

4. コードの解説:初心者でもわかる「ここがポイント!」

さあ、このコードが何をやっているのか、一つずつ丁寧に見ていきましょう。

# 4.1. 設定項目:ここを変えれば、あなたのツールになる!

' --- 設定項目 ---
    ' 配置したいシェイプの名前
    Const TARGET_SHAPE_NAME_TO_FIND As String = "サーバー"

    ' 検索対象とするステンシルファイルのパスとファイル名の配列
    Dim stencilPaths() As Variant
    stencilPaths = Array( _
        "C:\Users\YourUser\Documents\Visio\Custom Stencils\Network_Devices.vssx", _
        "C:\Users\YourUser\Documents\Visio\Custom Stencils\Servers.vssx", _
        "C:\Program Files\Microsoft Office\root\Visio Content\1041\Networking Basic Shapes.vssx" _
    )

    ' 配置先のページオブジェクト(アクティブなページを取得)
    Dim targetPage As Visio.Page
    Set targetPage = Visio.ActivePage

    ' 配置したいシェイプの配置座標 (X, Y)
    Dim targetX As Double
    Dim targetY As Double
    targetX = 2.0
    targetY = 4.0
  • `TARGET_SHAPE_NAME_TO_FIND`: ここに、あなたが探したいマスターシェイプの名前を正確に入力します。大文字・小文字は区別されません。
  • `stencilPaths`: ここが重要!検索したいステンシルファイル(`.vss` または `.vssx`)のフルパスを配列で指定します。`Array()` 関数を使って、複数のパスをカンマ区切りで列挙してください。あなたのPC環境に合わせて、このパスは必ず修正してくださいね!
  • `targetPage As Visio.Page`: `Visio.ActivePage` は、現在Visioでアクティブになっている(一番手前に表示されている)ページを指します。特別な理由がなければ、これでOKです。
  • `targetX`, `targetY`: シェイプを配置したいページの座標です。Visioの座標系は、ページの中心が (0,0) になります。正の値は右(X軸)と上(Y軸)方向、負の値は左と下方向です。単位はVisioの内部単位(通常はインチ)ですが、ここでは相対的な位置として指定します。`2.0` や `4.0` といった数値で指定します。

# 4.2. ステンシルの読み込みループ

' 1. 指定されたステンシルをループ処理で開く(読み込む)
    Debug.Print "--- ステンシルの読み込み開始 ---"
    For i = LBound(stencilPaths) To UBound(stencilPaths)
        Dim currentStencilPath As String
        currentStencilPath = stencilPaths(i)

        'ステンシルファイルが存在するかチェック
        If Dir(currentStencilPath) = "" Then
            errorMessage = errorMessage & "エラー: ステンシルファイルが見つかりません - " & currentStencilPath & vbCrLf
            Debug.Print "警告: ステンシルファイルが見つかりません - " & currentStencilPath
            GoTo NextStencil ' 次のステンシルへ
        End If

        'ステンシルが既に開かれているかチェック
        Dim existingStencil As Visio.Stencil
        Dim isAlreadyOpen As Boolean
        isAlreadyOpen = False
        For Each existingStencil In Visio.Stencils
            'ステンシルのURI(Uniform Resource Identifier)で比較すると正確
            If LCase(existingStencil.URI) = LCase("file://" & currentStencilPath) Then
                isAlreadyOpen = True
                Debug.Print "情報: ステンシルは既に開かれています - " & currentStencilPath
                Exit For
            End If
        Next existingStencil

        ' まだ開かれていない場合のみ、ステンシルを読み込む
        If Not isAlreadyOpen Then
            On Error Resume Next ' エラーが発生しても処理を続行
            Dim addedStencil As Visio.Stencil
            Set addedStencil = Visio.Stencils.Add(currentStencilPath)
            If Err.Number <> 0 Then
                errorMessage = errorMessage & "エラー: ステンシルの読み込みに失敗しました - " & currentStencilPath & " (エラーコード: " & Err.Number & ")" & vbCrLf
                Debug.Print "エラー: ステンシルの読み込みに失敗しました - " & currentStencilPath & " (エラーコード: " & Err.Number & ")"
                Err.Clear
            Else
                Debug.Print "成功: ステンシルを読み込みました - " & currentStencilPath
            End If
            On Error GoTo 0 ' 通常のエラーハンドリングに戻す
        End If
NextStencil:
    Next i
    Debug.Print "--- ステンシルの読み込み完了 ---"
  • `For i = LBound(stencilPaths) To UBound(stencilPaths)`: 設定した `stencilPaths` 配列の最初から最後まで、一つずつステンシルファイルのパスを取り出して処理します。`LBound` は配列の最小インデックス、`UBound` は最大インデックスを取得します。
  • `Dir(currentStencilPath) = “”`: `Dir` 関数は、指定されたファイルが存在すればファイル名を、存在しなければ空文字列 (`””`) を返します。これで、ファイルが存在しない場合にエラーメッセージを表示し、`GoTo NextStencil` で次のステンシル処理へスキップします。
  • ステンシルが既に開かれているかのチェック:
  • `For Each existingStencil In Visio.Stencils`: 現在Visioに読み込まれている(開かれている)すべてのステンシルを調べます。
  • `existingStencil.URI`: ステンシルのURI(Uniform Resource Identifier)を取得します。これは `file://C:\パス\ファイル名.vssx` のような形式になります。このURIで比較するのが、ファイルパスで直接比較するよりも正確です。
  • `If LCase(existingStencil.URI) = LCase(“file://” & currentStencilPath)`: 大文字・小文字を区別せずにURIが一致するかどうかを確認します。一致すれば `isAlreadyOpen = True` とし、ループを抜けます。
  • `If Not isAlreadyOpen Then … End If`: もしステンシルがまだ開かれていなければ、`Visio.Stencils.Add(currentStencilPath)` を実行してステンシルを読み込みます。
  • `On Error Resume Next` と `On Error GoTo 0`:
  • `On Error Resume Next`: この行以降でエラーが発生しても、VBAは処理を停止せず、次の行へ進みます。これは、ステンシルの読み込みに失敗した場合などに、プログラム全体がクラッシュするのを防ぐためです。
  • `Err.Number <> 0`: エラーが発生したかどうかを `Err.Number` で確認します。0以外であればエラーが発生しています。
  • `Err.Clear`: エラー情報をクリアします。
  • `On Error GoTo 0`: 通常のエラーハンドリングに戻します。これ以降でエラーが発生した場合は、VBAはデフォルトの動作(エラーメッセージを表示して停止)に戻ります。
  • `Set addedStencil = Visio.Stencils.Add(currentStencilPath)`: これがステンシルをプログラムで読み込むための重要なメソッドです! `Application.Stencils` コレクションに、指定したパスのステンシルファイルを追加します。これにより、そのステンシル内のマスターシェイプにアクセスできるようになります。
  • `Debug.Print`: これは、VBAエディタの「イミディエイトウィンドウ」(Ctrl+Gで表示)にメッセージを出力するためのものです。プログラムの実行状況を確認するのに非常に役立ちます。

# 4.3. マスターシェイプの検索ループ

' 2. 読み込んだステンシルの中から、目的のマスターシェイプを検索する
    Debug.Print "--- マスターシェイプの検索開始 ('" & TARGET_SHAPE_NAME_TO_FIND & "') ---"
    For Each foundMasterShape In Visio.Masters
        ' マスターシェイプの名前を小文字に変換して比較
        If LCase(foundMasterShape.Name) = lowerTargetShapeName Then
            foundFlag = True
            Debug.Print "発見: マスターシェイプ '" & foundMasterShape.Name & "' を見つけました。"
            Exit For ' 見つかったらループを抜ける
        End If
    Next foundMasterShape
    Debug.Print "--- マスターシェイプの検索完了 ---"
  • `For Each foundMasterShape In Visio.Masters`: `Visio.Masters` コレクションは、現在Visioアプリケーションで利用可能なすべてのマスターシェイプ(開かれているドキュメント内のマスター、開かれているステンシル内のマスターなど)を含んでいます。このコレクションをループすることで、目的のマスターシェイプを効率的に検索できます。
  • `If LCase(foundMasterShape.Name) = lowerTargetShapeName Then`: 各マスターシェイプの `Name` プロパティ(マスターシェイプの名前)を小文字に変換し、設定した `lowerTargetShapeName` と一致するかどうかを比較します。
  • `foundFlag = True`: マスターシェイプが見つかったら、フラグを `True` に設定します。
  • `Exit For`: 目的のマスターシェイプが見つかったら、それ以上検索する必要はないので、ループを抜けます。

# 4.4. シェイプの配置

' 3. 見つかったマスターシェイプを指定座標に配置する
    If foundFlag Then
        Debug.Print "--- シェイプの配置開始 ---"
        On Error Resume Next ' 配置時のエラーを無視(例: ページが無効など)
        Set placedShape = targetPage.Drop(foundMasterShape, targetX, targetY)

        If Err.Number <> 0 Then
            errorMessage = errorMessage & "エラー: マスターシェイプ '" & foundMasterShape.Name & "' の配置に失敗しました。 (エラーコード: " & Err.Number & ")" & vbCrLf
            Debug.Print "エラー: マスターシェイプ '" & foundMasterShape.Name & "' の配置に失敗しました。 (エラーコード: " & Err.Number & ")"
            Err.Clear
        Else
            Debug.Print "成功: マスターシェイプ '" & foundMasterShape.Name & "' を (" & targetX & ", " & targetY & ") に配置しました。"
            ' 配置後のシェイプに対する追加処理があれば、ここで行う
            ' 例: シェイプのテキストを変更する
            ' placedShape.Text = "配置された " & foundMasterShape.Name
        End If
        On Error GoTo 0 ' 通常のエラーハンドリングに戻す
        Debug.Print "--- シェイプの配置完了 ---"
    Else
        errorMessage = errorMessage & "情報: 指定されたマスターシェイプ '" & TARGET_SHAPE_NAME_TO_FIND & "' は、開かれたステンシルの中に見つかりませんでした。" & vbCrLf
        Debug.Print "情報: 指定されたマスターシェイプ '" & TARGET_SHAPE_NAME_TO_FIND & "' は、開かれたステンシルの中に見つかりませんでした。"
    End If
  • `If foundFlag Then … End If`: マスターシェイプが見つかった場合のみ、配置処理を実行します。
  • `Set placedShape = targetPage.Drop(foundMasterShape, targetX, targetY)`: これがマスターシェイプをページに配置するメソッドです!
  • `targetPage`: 配置先のページオブジェクト。
  • `foundMasterShape`: 配置したいマスターシェイプオブジェクト。
  • `targetX`, `targetY`: 配置したい座標。

このメソッドは、配置された実際の図形(`Shape` オブジェクト)を返します。この返された `placedShape` オブジェクトを使って、配置後のシェイプのテキストを変更したり、プロパティを調整したりすることができます。

  • `On Error Resume Next` / `On Error GoTo 0`: ここでも、配置処理中に予期せぬエラー(例えば、`targetPage` が無効だったり、`foundMasterShape` が何らかの理由で配置できなかったりする場合)が発生しても、プログラムが停止しないようにしています。

# 4.5. 結果の表示

' --- 結果の表示 ---
    If errorMessage <> "" Then
        MsgBox "処理中に以下の問題が発生しました:" & vbCrLf & errorMessage, vbExclamation, "シェイプ配置ツール - 結果"
    Else
        MsgBox "指定されたシェイプの配置が完了しました。", vbInformation, "シェイプ配置ツール - 完了"
    End If
  • `MsgBox`: 処理の最後に、ユーザーに結果を通知するためのメッセージボックスを表示します。エラーが発生した場合はエラーメッセージを、問題なく完了した場合は完了メッセージを表示します。

5. 陥りやすいエラーとその対処法:先輩エンジニアからのアドバイス

このツールを作成・実行する上で、いくつか注意しておきたい点や、よくあるエラーがあります。

# 5.1. ファイルパスの間違い

  • 症状: 「ステンシルファイルが見つかりません」というエラーメッセージが表示される。
  • 原因: `stencilPaths` 配列に指定したステンシルファイルのパスが間違っている、またはファイルが存在しない。
  • 対処法:
  • 指定したパスに、実際にそのファイルが存在するかどうかをエクスプローラーで確認してください。
  • パスの区切り文字(`\`)が正しいか確認してください。
  • ファイル名に誤字脱字がないか確認してください。
  • 必要であれば、`Debug.Print currentStencilPath` を追加して、実際にVBAが参照しようとしているパスを確認してください。

# 5.2. マスターシェイプ名の間違い

  • 症状: 「指定されたマスターシェイプが見つかりませんでした」という情報メッセージが表示される、または何も配置されない。
  • 原因: `TARGET_SHAPE_NAME_TO_FIND` に指定したマスターシェイプの名前が、ステンシル内の実際の名前と一致しない。
  • 対処法:
  • Visioで該当のステンシルを開き、マスターシェイプの名前を正確に確認してください。
  • 大文字・小文字は区別されませんが、スペルミスがないか、余分なスペースが入っていないかなどを注意深く確認してください。
  • マスターシェイプの名前は、ステンシルのコンテキストメニューから「編集」を選び、シェイプのタイトルバーで確認できます。

# 5.3. Visioのバージョン互換性

  • 症状: 特定のステンシルファイル(特に古い `.vss` ファイル)が読み込めない、またはエラーが発生する。
  • 原因: `.vssx` はXMLベースの新しい形式ですが、古い `.vss` ファイルは異なる形式です。Visioのバージョンによっては、古い形式のステンシルの扱いに制限がある場合があります。
  • 対処法:
  • 可能であれば、古い `.vss` ファイルをVisioで開き、新しい `.vssx` 形式で保存し直してみてください。
  • それでも問題が解決しない場合は、そのステンシルファイル固有の問題である可能性も考えられます。

# 5.4. パフォーマンスの問題

  • 症状: 多数のステンシルを読み込んだり、検索したりする際に、処理に時間がかかる。
  • 原因:
  • `Visio.Masters` コレクションは、開いているすべてのマスターシェイプを保持するため、非常に大きくなることがあります。
  • 大量のステンシルファイルを一つずつ `Visio.Stencils.Add` する処理は、それなりに時間がかかります。
  • 対処法:
  • 検索対象を絞る: 可能な限り、検索対象とするステンシルファイルの数を減らしましょう。
  • マスターシェイプの検索方法の最適化: もし、特定のステンシルにのみ目的のシェイプがあると分かっている場合は、`Visio.Masters` 全体を検索するのではなく、そのステンシルオブジェクトの `Masters` コレクションを直接検索する方が効率的です。
' 例: 特定のステンシル (myTargetStencil) 内のマスターシェイプを検索する場合
        Dim specificMaster As Visio.Master
        Dim myTargetStencil As Visio.Stencil
        ' ... myTargetStencil が既に取得されているとする ...
        For Each specificMaster In myTargetStencil.Masters
            If LCase(specificMaster.Name) = lowerTargetShapeName Then
                ' 見つかった!
                Exit For
            End If
        Next specificMaster
  • ステンシルの後処理: 不要になったステンシルは、プログラムの最後に `stencil.Close` メソッドで閉じることで、メモリを解放し、パフォーマンスの改善につながる場合があります。ただし、頻繁に開閉するのは逆にオーバーヘッドになることもあるので、状況に応じて判断してください。

6. さらなる応用:このツールを「自分仕様」に進化させる!

今回作成したツールは、あくまで基本形です。ここから、あなたの業務に合わせてさらに便利に進化させることができます!

# 6.1. 複数のシェイプを一度に配置する

' 配置したいシェイプの名前と座標のペアの配列
Dim shapesToPlace() As Variant
shapesToPlace = Array( _
    Array("サーバー", 2.0, 4.0), _
    Array("ルーター", -2.0, 4.0), _
    Array("スイッチ", 0.0, 2.0) _
)

' ... (ステンシル読み込み処理は同じ) ...

' 3. 見つかったマスターシェイプを指定座標に配置する (複数シェイプ対応)
Dim shapeInfo As Variant
Dim foundMaster As Visio.Master ' 見つかったマスターシェイプを保持する変数
Dim placedShape As Visio.Shape

' shapesToPlace 配列をループ
For Each shapeInfo In shapesToPlace
    Dim shapeName As String
    Dim posX As Double
    Dim posY As Double

    shapeName = CStr(shapeInfo(0)) ' シェイプ名
    posX = CDbl(shapeInfo(1))     ' X座標
    posY = CDbl(shapeInfo(2))     ' Y座標

    Set foundMaster = Nothing ' 検索前に初期化
    Dim master As Visio.Master
    ' Visio.Masters コレクションからシェイプを検索
    For Each master In Visio.Masters
        If LCase(master.Name) = LCase(shapeName) Then
            Set foundMaster = master
            Exit For ' 見つかったらループを抜ける
        End If
    Next master

    If Not foundMaster Is Nothing Then
        ' 配置処理
        On Error Resume Next
        Set placedShape = targetPage.Drop(foundMaster, posX, posY)
        If Err.Number <> 0 Then
            errorMessage = errorMessage & "エラー: マスターシェイプ '" & shapeName & "' の配置に失敗しました。 (エラーコード: " & Err.Number & ")" & vbCrLf
            Err.Clear
        Else
            Debug.Print "成功: マスターシェイプ '" & shapeName & "' を (" & posX & ", " & posY & ") に配置しました。"
        End If
        On Error GoTo 0
    Else
        errorMessage = errorMessage & "情報: マスターシェイプ '" & shapeName & "' は見つかりませんでした。" & vbCrLf
    End If
Next shapeInfo

このように、配置したいシェイプ名と座標をペアにした配列を用意すれば、一度の実行で複数のシェイプを配置できます。

# 6.2. 配置後のシェイプの整列

配置したシェイプを、さらにきれいに整列させたい場合もありますよね。VBAでは、配置済みのシェイプに対して、`CellsU` プロパティなどを利用して位置やサイズを細かく制御できます。

例えば、配置したシェイプをすべて水平方向に一列に並べたい場合は、最初のシェイプの Y 座標を基準に、他のシェイプの Y 座標を調整する、といった処理が考えられます。

# 6.3. ユーザーインターフェースの追加

毎回コードを編集するのは少し面倒ですよね。そこで、ユーザーフォーム(UserForm)を作成し、配置したいシェイプ名やステンシルパス、座標などをGUIで入力できるようにすると、より使いやすいツールになります。

まとめ:Visio VBAで「できること」が格段に広がる!

いかがでしたでしょうか?今回は、複数のステンシルから目的のマスターシェイプを検索し、ページに一括配置する自動化ツールの作成に挑戦しました。

  • Visioのオブジェクトモデルにおける、ステンシルとマスターシェイプの関係性を理解しました。
  • `Application.Stencils.Add` メソッドでステンシルをプログラムから読み込む方法を学びました。
  • `Visio.Masters` コレクションを利用して、目的のマスターシェイプを効率的に検索する方法を習得しました。
  • `Page.Drop` メソッドで、マスターシェイプをページに配置する方法をマスターしました。
  • よくあるエラーとその対処法についても解説しました。

このツールを使いこなせるようになれば、Visioでの図面作成作業は格段に効率化され、あなたの業務遂行能力は飛躍的に向上するはずです。
「マクロの記録」だけでは到達できなかった、より高度な自動化の世界へようこそ!
ぜひ、このコードをベースに、ご自身の業務に合わせてカスタマイズしてみてください。

Visio VBAの世界は奥深く、まだまだたくさんの可能性を秘めています。
このブログが、皆さんのVisio VBAマスターへの道のりにおいて、確かな一歩となることを願っています。

それでは、また次回のブログでお会いしましょう!Happy Visio VBA Coding!

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