【入門編】【実務直結】ページ追加時に「自動採番」を行うためのカウンター管理と、重複ページ名の防止策 – Visio VBA解析バイブル

スポンサーリンク
スポンサーリンク

【実務直結】Visio VBAで「ページ名重複エラー」を根絶する:賢い自動採番ロジックの設計術

こんにちは。現場の自動化を支えるエンジニアの皆さん。
「マクロの記録」から一歩踏み出し、自分自身のコードでVisioを操ろうとしている今のあなたは、まさにエンジニアとしての「脱皮」の真っ最中ですね。素晴らしい挑戦です。

しかし、いざ「ページを自動で追加していくマクロ」を組もうとすると、必ずと言っていいほど一つの壁にぶつかります。

「実行時エラー ‘2147016040’: この名前は既に使用されています」

ページ名を「Page-1」のように固定で指定して追加しようとしたとき、すでにその名前のページが存在していると、Visioは「そんな名前はもう使えないよ!」と怒って止まってしまうのです。

今日は、このエラーをスマートに回避し、プロの現場でも通用する「既存のページ名を走査して、絶対に重複しないユニークな名前を自動生成するロジック」を伝授します。

ここをクリアすれば、あなたのVisio VBAは「ただの記録」から「自律的なシステム」へと進化しますよ。

1. なぜ「エラー回避」ではなく「ロジック」が必要なのか

初学者の皆さんが陥りがちなのが、`On Error Resume Next` という魔法の言葉を使って、エラーを無理やり無視する方法です。

' ⚠️ 初心者が陥りがちな、避けるべき書き方
On Error Resume Next
ActiveDocument.Pages.Add.Name = "Step-1"
On Error GoTo 0

これでは、エラーが起きたときに「なぜ失敗したのか」が分からず、後からデバッグ(修正)ができなくなります。また、意図しない名前でページが作成されてしまうこともあります。

プロの設計思想は違います。
「エラーが起きる前に、エラーが起きない条件を計算して提示する」。
これが、堅牢なプログラムを作るための鉄則です。

2. アルゴリズムの設計図(思考プロセス)

重複を防ぐためのロジックは、以下の3ステップで考えます。

1. スキャン(走査): 現在のドキュメントにある全ページの名前をチェックする。
2. シミュレーション(試行): 「もし `Prefix-1` という名前にしたら重複するか?」を仮定する。
3. 決定: 重複がなければその名前を採用し、重複していれば数字を `+1` して再度チェックする。

これを図解すると、以下のようになります。

[開始]
  ↓
[ベースとなる名前(例: "Task-")と開始番号(1)を用意]
  ↓
[ループ開始]
  ├─ 「Task-1」という名前が既存ページの中に存在するか?
  │    ├─ YES (重複あり) → 番号を 2 に増やしてループの先頭へ戻る
  │    └─ NO (重複なし) → この名前を「採用」として次に進む
  ↓
[新しいページを「採用した名前」で作成]
  ↓
[終了]

3. 実装:ユニークなページ名生成関数

では、実際に使えるコードを見てみましょう。
今回は、「ページ名を決める専用の関数(Function)」を切り分けて作る、メンテナンス性の高い書き方を提示します。

Option Explicit

''' <summary>
''' メイン処理:自動採番されたページを追加する
''' </summary>
Sub AddAutoNumberedPage()
    Dim newPageName As String
    Dim newPage As Visio.Page
    Dim prefix As String
    
    ' ページ名の接頭辞(Prefix)を設定
    prefix = "System_Step_"
    
    ' 1. 重複しない名前を関数で取得
    newPageName = GetUniquePageName(prefix)
    
    ' 2. 取得した名前で新しいページを追加
    ' ※Pages.Addの直後に名前をセットするのが確実です
    Set newPage = ActiveDocument.Pages.Add
    newPage.Name = newPageName
    
    ' 3. 完了通知(デバッグ用)
    MsgBox "新しいページを作成しました: " & newPageName, vbInformation, "完了"
End Sub

''' <summary>
''' 既存のページ名を走査し、重複しないユニークな名前を生成する
''' </summary>
''' <param name="prefix">名前の接頭辞(例: "Page-")</param>
''' <returns>重複しない名前(例: "Page-3")</returns>
Function GetUniquePageName(ByVal prefix As String) As String
    Dim i As Integer
    Dim counter As Integer
    Dim candidateName As String
    Dim exists As Boolean
    Dim pg As Visio.Page
    
    counter = 1
    exists = True
    
    ' 重複がないことが確認できるまでループを回す
    Do While exists
        ' 候補となる名前を作成 (例: "Step-1", "Step-2"...)
        candidateName = prefix & counter
        exists = False ' 一旦「存在しない」と仮定してチェックに入る
        
        ' ドキュメント内の全ページをループして名前を確認
        For Each pg In ActiveDocument.Pages
            ' 大文字小文字を区別せず、完全に一致するか判定
            If StrComp(pg.Name, candidateName, vbTextCompare) = 0 Then
                exists = True ' 重複が見つかった!
                Exit For      ' これ以上探す必要はないのでループを抜ける
            End If
        Next pg
        
        ' 重複があった場合は、カウンターを増やして再度チェック
        If exists Then
            counter = counter + 1
        End If
    Loop
    
    ' 最終的に決定した名前を返す
    GetUniquePageName = candidateName
End Function

4. プロの視点:コードの「重み」を理解する

このコードを書き上げたあなたに、さらに一段上の知識を授けましょう。

オブジェクトのライフサイクルとパフォーマンス

上記のコードでは `For Each pg In ActiveDocument.Pages` を使って全ページを走査しています。
ページ数が10枚、20枚程度なら一瞬ですが、もし数千枚の巨大な図面を扱う場合、この「ループの中でループを回す」処理は少しずつ重くなります。

しかし、「名前の重複チェック」という目的において、全ページを確認することは避けて通れない儀式です。重要なのは、`Exit For` を使って「見つかった瞬間に探索を止める」という記述を入れることです。これだけで、無駄な計算資源の消費を劇的に抑えられます。

`StrComp` を使う理由

名前の比較に `If pg.Name = candidateName Then` と書くこともできますが、私はあえて `StrComp(…, vbTextCompare)` を推奨します。
これは、Visio側で「page-1」と「PAGE-1」が同一視されるケース(大文字小文字の揺らぎ)に対処するためです。実務では、ユーザーが手動で名前を変えてしまうリスクが常にあります。「人間は間違えるもの」という前提に立つことが、最強のエンジニアへの第一歩です。

5. まとめ:ここをクリアすれば、次は自由です

今回のポイントを振り返りましょう。

1. エラーを無視するのではなく、事前に回避するロジックを組む。
2. 「名前を作る関数」と「ページを作る処理」を分離し、再利用性を高める。
3. 既存のページを走査し、重複がなくなるまでカウンターを回す。

この「ユニークな名前を生成する」という考え方は、Visioに限らず、Excel VBAでのシート操作や、ファイル出力の自動化など、あらゆる業務自動化に応用できる「普遍的な技術」です。

最初は難しく感じるかもしれません。でも、一度このパターンをマスターしてしまえば、もう「名前の重複」に怯えることはありません。

さあ、自信を持って、次の自動化プロジェクトに挑んでください。応援していますよ!

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