【実務直結】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でのシート操作や、ファイル出力の自動化など、あらゆる業務自動化に応用できる「普遍的な技術」です。
最初は難しく感じるかもしれません。でも、一度このパターンをマスターしてしまえば、もう「名前の重複」に怯えることはありません。
さあ、自信を持って、次の自動化プロジェクトに挑んでください。応援していますよ!
