Visio VBAの「魔の領域」を攻略する:Shapeコレクションの逆順ループという鉄則
こんにちは。自動化の世界へようこそ。
Visio VBAで図形(Shape)を操作し始めると、多くの人が最初にぶつかる壁があります。「特定の条件の図形だけを削除したいのに、なぜか一部の図形が消し残る」という現象です。
これ、実はあなたのコードのせいではなく、Visioのコレクション管理の仕組みによるものなのです。今回は、プロのエンジニアが必ず守っている「逆順ループ(Step -1)」という絶対原則について、その裏側を紐解いていきましょう。
—
なぜ「正順ループ」では図形が消し残るのか?
まずは、やってはいけない「悪い例」を見てください。
‘ 【NG例】インデックスがずれて処理がスキップされる
Dim i As Integer
For i = 1 To ActivePage.Shapes.Count
‘ 条件に合致したら削除
If ActivePage.Shapes(i).Name Like “DeleteMe_” Then
ActivePage.Shapes(i).Delete
End If
Next i
なぜこれが失敗するのか?
Visioの`Shapes`コレクションは、インデックス(1, 2, 3…)という番号で管理されています。
1. インデックス「1」の図形を削除すると、インデックス「2」だった図形が自動的に繰り上がり、新しい「1」になります。
2. 次のループで、プログラムはインデックス「2」を見に行きます。
3. その結果、元々「2」だった図形は飛ばされ、元々「3」だった図形が処理されることになります。
つまり、図形を削除するたびに、本来処理すべき図形が「左(前)」へ逃げていく。これが、一部の図形が消し残る(あるいはインデックスエラーで止まる)正体です。
—
解決策:逆順ループ(Step -1)こそが「絶対正義」
図形を消すなら、後ろから消す。これがVisio開発の鉄則です。
後ろから消せば、インデックスがずれるのは「まだ処理していない前方」の図形だけ。すでに処理が終わった「後方」のインデックスには何の影響もありません。
安全で確実なコードパターン
現場でそのまま使える、洗練された削除ロジックがこちらです。
Sub DeleteSpecificShapes()
Dim pg As Visio.Page
Dim i As Integer
Set pg = ActivePage
‘ 重要:Countから1まで、Step -1 で逆方向にループする
For i = pg.Shapes.Count To 1 Step -1
‘ 削除対象かどうか判定(例: 名前に “Target” を含む図形)
If InStr(pg.Shapes(i).Name, “Target”) > 0 Then
‘ 確実かつ安全に削除
pg.Shapes(i).Delete
End If
Next i
Debug.Print “クリーンアップ完了しました。”
End Sub
コードの解説
- `For i = pg.Shapes.Count To 1 Step -1`: これが肝です。最後尾の番号からスタートし、インデックスが減っていくたびに、まだ触れていない図形との整合性を保ちます。
- `Step -1`: これを書き忘れると動きません。忘れずに書いてくださいね。
- オブジェクトの直指定: `pg.Shapes(i)` とすることで、現在ループしているインデックスを確実にターゲットできます。
—
さらに高度なエンジニアを目指すあなたへ
この「逆順ループ」の考え方は、削除だけでなく、図形の挿入を伴う処理にも応用可能です。
例えば、ある図形の下に新しい図形を次々と追加していくような処理を行う場合も、正順で行うとコレクションの順序が激しく入れ替わり、制御不能に陥ります。コレクションを操作する際は、「今行っている操作が、コレクションのインデックスにどう影響するか?」を常にイメージする癖をつけましょう。
まとめ:今日から使えるチェックリスト
1. 削除処理なら `Step -1`: これを忘れたらバグの温床になります。
2. インデックスは常に変動する: `Shapes(i)` をキャッシュ(変数に代入)して使い回すときは特に注意してください。
3. まずはこのパターンで: マクロの記録から脱却する第一歩は、この「コレクションの制御権」を自分で握ることです。
Visioはオブジェクトモデルが非常に奥深く、美しい世界です。この「逆順ループ」を指先が覚えるまで繰り返せば、あなたはもう、ただの初心者ではありません。
何か分からないことがあれば、いつでも聞いてください。一緒に最強の自動化環境を構築していきましょう!
