Visio VBAの「全舐め検索」はもう卒業! `Page.FindShapes` で実現する爆速エンジニアリング
こんにちは。自動化の深淵へようこそ。
Visioで数千個のシェイプを扱う図面を操作する際、多くの人が陥る罠があります。それは、`For Each shp In ActivePage.Shapes` と書いて、全てのシェイプを一つずつ条件判定する「全舐めループ」です。
図面が小さいうちはいいでしょう。しかし、数千、数万のシェイプを抱える大規模システム図でそれをやれば、処理が終わる頃にはコーヒーを飲み終えて休憩から戻ってきてもまだ止まっているかもしれません。
今日は、Visioの心臓部にある「検索エンジン」を直接叩くことで、数秒かかっていた処理を数ミリ秒で完了させるための禁断の奥義、`Page.FindShapes` について伝授します。
—
なぜ「ループ」ではなく「FindShapes」なのか?
VBAのループでシェイプを回すということは、Visioが持つ内部データ構造(メモリ)に一つずつアクセスし、VBAの変数にオブジェクトをロードするという「オーバーヘッド」を繰り返す行為です。
一方で、`Page.FindShapes` は、Visio内部の最適化された検索ルーチンを呼び出し、条件に合致したシェイプのリスト(配列)を一括で返します。いわば、図書館で全棚を歩き回るのと、司書に「このキーワードの本全部持ってきて」と頼むのとの違いです。
爆速検索の基本コード
まずは、特定の文字列を含むシェイプを瞬時に見つけるコードを見てみましょう。
Sub FindShapesFast()
Dim vsoPage As Visio.Page
Dim vsoShapes() As Visio.Shape
Dim i As Long
Set vsoPage = ActivePage
‘ 検索条件を指定して抽出
‘ 第1引数: 検索対象(全シェイプ)
‘ 第2引数: 検索ルール(ここではテキスト検索)
‘ 第3引数: 検索キーワード
‘ 第4引数: 結果を格納する配列(戻り値)
vsoPage.FindShapes Visio.VisFindTypes.visFindText, “キーワード”, vsoShapes
‘ 配列が空でないか確認(重要!)
If (Not vsoShapes) <> -1 Then
For i = LBound(vsoShapes) To UBound(vsoShapes)
‘ 見つかったシェイプへの処理
Debug.Print “発見: ” & vsoShapes(i).Name
vsoShapes(i).Cells(“FillForegnd”).Formula = “RGB(255,0,0)”
Next i
Else
MsgBox “条件に合致するシェイプは見つかりませんでした。”
End If
End Sub
このコードの「本質的なポイント」
1. 動的配列の戻り値: `FindShapes` は結果を `Variant` 型の配列として返します。`vsoShapes()` という宣言がポイントです。
2. `Not vsoShapes <> -1` の呪文: VBAにおいて「配列が初期化されているか(空ではないか)」を判定する、VBAエンジニアの常套句です。これを使わずに `UBound` を呼ぶと、空の時にエラーで落ちます。
3. APIレベルのフィルタリング: `visFindTypes` を変えるだけで、検索対象を柔軟に変更可能です。
- `visFindText`: シェイプ内のテキスト
- `visFindLayer`: 特定のレイヤーに属するシェイプ
- `visFindMaster`: 特定のマスターシェイプから作成された図形
—
初学者が陥りやすい「3つの罠」
いくら高速でも、使い方を間違えればバグの温床になります。ここをクリアすれば、あなたはもう中級者です。
1. グループ化されたシェイプの扱い
`FindShapes` はグループ(`Group`)の内側まで深掘りするべきかを制御できます。通常は `visFindDeep` を組み合わせることで、グループ内のシェイプまで網羅的に検索可能です。
2. 条件の不整合による型変換エラー
「テキストがないシェイプ」に対してテキスト検索をかけると、Visioは内部で最適化して無視してくれますが、複雑な条件を組み合わせるとエラーになることがあります。検索する対象の型(`VisFindTypes`)と、狙っているシェイプのプロパティが一致しているか常に意識してください。
3. 処理中の画面更新
大量のシェイプを検索した後に一括で色を変えたりする場合、`Application.ScreenUpdating = False` を忘れずに。これだけで、実行速度は体感でさらに数倍速くなります。
—
次のステージへ
`FindShapes` を使いこなせるようになると、次にやりたくなるのは「複数の条件」での検索でしょう。例えば「特定のレイヤーにあり、かつ特定のテキストを含むもの」といった条件です。
残念ながら `FindShapes` 単体では複雑な論理演算はできません。その場合は、`FindShapes` で「レイヤー」で絞り込んだ後、その結果セットに対して `If` 文でテキスト判定を行う「二段階フィルタリング」を推奨します。これが、メモリ効率と実行速度のバランスを取る、プロの作法です。
Visio VBAは、ただの「自動化ツール」ではなく、図面という「データベース」を操る高度なインターフェースです。このコードが、あなたの業務を劇的に改善する一歩になることを確信しています。
さあ、次はどんな複雑な図面を料理しましょうか? 困ったことがあれば、またいつでも聞いてください。応援していますよ。
