【Visio VBA】なぜShapeの「逆順ループ」が絶対正義なのか? 破壊的変更を安全に制御する極意
業務自動化の現場でVisio VBAを触っていると、必ず突き当たる壁がある。「図形の削除」や「動的な追加」を含むループ処理だ。
「なぜか一部の図形が削除されずに残る」「ループの途中でインデックスエラーが出る」。そんな怪奇現象に頭を抱えたことはないだろうか? それはVisioのメモリ管理やオブジェクトモデルの特性を理解していない者が陥る、典型的な地雷だ。
今回は、Visioの`Shapes`コレクションを自在に操り、バグを生まないための「逆順ループ」という絶対原則について、その深淵を解説する。
—
1. なぜ「順方向(For i = 1 To Count)」は破滅を招くのか
Visioの`Page.Shapes`は、インデックスによって管理されている。ここで重要なのは、「図形を削除すると、後ろに続く図形のインデックスが自動的に繰り上がる」という仕様だ。
悲劇のシナリオ
1. `i=1`の図形を削除する。
2. 元々`i=2`だった図形が、`i=1`の座にスライドする。
3. ループが`i=2`へ進む。
4. 結果、元々`i=2`だった図形(今は`i=1`)はチェックされないままスキップされる。
この「間引き」現象は、複雑な図面になるほど致命的なバグを引き起こす。データベースから取り込んだデータをVisioで可視化する際、古い図形が残存したまま新しい図形が重なり、ファイルサイズが肥大化したり、整合性が崩壊したりする原因のトップだ。
—
2. 解決策:絶対原則「逆順ループ(Step -1)」
この問題に対する唯一かつエレガントな解法が、`Step -1`を用いた逆順走査だ。
後ろから削除していくことで、たとえインデックスが繰り上がったとしても、それは「既に処理が終わった領域」でしかない。これから処理すべき「前のインデックス」には一切影響を与えないのだ。
プロダクションコード例:堅牢な削除ルーチン
現場でそのまま使える、型安全で保守性の高いコードを提示する。
‘ @brief ページ内の特定の条件を満たす図形を安全に削除する
‘ @param targetPage 処理対象のVisio Pageオブジェクト
Public Sub SafeDeleteShapes(ByRef targetPage As Visio.Page)
Dim i As Long
Dim shp As Visio.Shape
‘ 必ず Count から 1 まで Step -1 で走査する
For i = targetPage.Shapes.Count To 1 Step -1
Set shp = targetPage.Shapes(i)
‘ 例:特定の名前やプロパティを持つ図形のみを対象にする場合
‘ 開発者へ:ここで条件を厳格に定義すること
If InStr(shp.Name, “Temp_”) > 0 Then
‘ 削除処理
shp.Delete
End If
Next i
Debug.Print “クリーンアップ完了。”
End Sub
—
3. 実務で勝つための「3つの鉄則」
単に逆順でループするだけでは、真のプロフェッショナルとは言えない。大規模なVisio自動化を成功させるための知見を授ける。
① 常に「オブジェクト」を直接参照する
インデックス経由で`Shapes(i)`を何度も呼び出すのは、パフォーマンス上もあまり賢くない。`For Each`が使える場面ならそちらを優先すべきだが、削除を含むならやはり`Step -1`だ。その際、必ず`Set shp = …`でオブジェクトをキャッシュしてから属性判定を行うこと。
② データベース連携時は「識別子」を徹底せよ
DBから図形を再生成する場合、`Name`プロパティだけに頼るな。Visioの`Shape.UniqueID`を活用し、DB側の主キーと紐付けるのが鉄則だ。図形が削除された後の再生成時に、既存図形を消し忘れるリスクを最小化できる。
③ エラーハンドリングの忘却は死を招く
Visioのオブジェクトモデルは、時として「保護された図形」や「グループ化された図形」によって予期せぬエラーを吐く。`On Error Resume Next`で誤魔化すのではなく、`shp.OneD`(1次元か否か)や`shp.Type`をチェックし、削除可能な状態かを確認するロジックを挟むのが、真に「堅牢」な設計だ。
—
最後に:エンジニアとしての矜持
「動けばいい」というコードは、数ヶ月後の自分を殺す。特にVisioのようにドキュメントの状態が複雑に変化する環境では、「コレクションの整合性をどう保つか」という視点を持っているかどうかが、そのエンジニアの価値を決める。
逆順ループは、単なるテクニックではない。「破壊的変更に対して、いかに影響範囲を限定させるか」という、システム設計の基本思想そのものだ。
君たちが書くそのコードが、誰かの業務を劇的に効率化することを期待している。さあ、IDEを開き、美しいループを実装しよう。
