【実務・中級編】条件に合致するシェイプの超高速検索:Page.FindShapesを用いたAPIレベルのフィルタリング処理 – Visio VBA解析バイブル

スポンサーリンク

Visio VBAの「全舐めループ」は卒業せよ:Page.FindShapesによる極限の高速化戦術

Visioの図面が巨大化するにつれ、VBAコードが「フリーズしたかのような重さ」に陥る経験はないだろうか。多くの開発者が犯す最大の過ちは、`ActivePage.Shapes`を`For Each`で回し、すべてのシェイプに対して`If`文で属性を確認するという「総当たり戦法」だ。

数千のシェイプを持つ図面でそれをやれば、CPUは不要なオブジェクトの走査に忙殺される。我々プロフェッショナルは、Visioのエンジンが内部で管理するインデックスを直接叩くべきだ。それが`Page.FindShapes`メソッドである。

今日は、この「APIレベルのフィルタリング」を使いこなし、業務自動化ツールをプロの品質へ引き上げるための極意を伝授する。

なぜ `For Each` が悪なのか

`ActivePage.Shapes`で全シェイプを取得する際、Visioはメモリ上の全オブジェクトをVBA側にバインド(マーシャリング)しようとする。これは重い。特に、グループ化されたシェイプや、複雑なメタデータを持つシェイプが混在している場合、このオーバーヘッドは無視できない。

`Page.FindShapes`は、Visioの描画エンジンが持つクエリ機能を利用する。つまり、「条件に合致するものだけを、ネイティブの速度で抽出する」のだ。

Page.FindShapesの極限活用:プロダクションコード

以下のコードは、指定したテキストを含むシェイプを、総当たりをせずに爆速で抽出する実務用テンプレートだ。

Option Explicit

”’

”’ 指定したテキストを含むシェイプを高速検索し、配列で返す
”’

Public Sub SearchShapesOptimized()
Dim vsoPage As Visio.Page
Dim vsoShapes() As Visio.Shape
Dim i As Long

Set vsoPage = ActivePage

‘ 第1引数: 検索対象 (1=テキスト, 2=名前, etc.)
‘ 第2引数: 検索キーワード
‘ 第3引数: 検索オプション (16=完全一致, 32=部分一致)
‘ 第4引数: 結果格納用配列

On Error Resume Next ‘ 空の結果が返る可能性を考慮
vsoPage.FindShapes visFindText, “検索ターゲット”, visFindText + visFindPartial, vsoShapes

If Err.Number <> 0 Then
Debug.Print “対象のシェイプは見つかりませんでした。”
Exit Sub
End If
On Error GoTo 0

‘ 抽出したシェイプに対する処理(ここは最小限のロジックに留める)
For i = LBound(vsoShapes) To UBound(vsoShapes)
Debug.Print “発見: ” & vsoShapes(i).Name & ” / ID: ” & vsoShapes(i).ID
‘ ここでプロパティ変更やデータ連携を行う
Next i
End Sub

この設計の「魂」:なぜこれが堅牢なのか

1. メモリ効率の最適化: 配列(`vsoShapes`)にポインタだけが格納されるため、不要なオブジェクトのインスタンス化を最小限に抑えられる。
2. 型定義の明確化: `Visio.Shape`の配列として受け取ることで、VBAのIntelliSenseが効き、保守性が飛躍的に向上する。
3. エラーハンドリング: `FindShapes`は対象が見つからない場合にエラーを投げる仕様がある。`On Error Resume Next`を適切に配置し、空の結果を「異常系」としてハンドリングする設計が、予期せぬクラッシュを防ぐ。

実務で陥る「罠」と回避策

1. データベース・外部ファイル連携の注意点

検索結果をExcelやDBに書き出す際、`vsoShapes(i)`のプロパティを都度読み取るとボトルネックになる。「検索はFindShapesで高速化し、読み取りは一括して行う」のが鉄則だ。データ量が多い場合は、`Shape.CellsSRC`を直接操作するのではなく、`Shape.Data1`(ユーザー定義セル)を活用した一括バルク更新を検討すべきである。

2. レイヤーフィルタリングとの組み合わせ

特定のレイヤーにあるシェイプのみを対象にしたい場合、`FindShapes`単体では難しい。この場合は、`FindShapes`で候補を絞り込んだ後、`Shape.Layer`プロパティで後段フィルタリングを行う。
「すべてをループさせる」のと、「`FindShapes`で絞り込んだ結果をさらに絞り込む」のとでは、計算量は桁違いに変わる。

チーフアーキテクトからの助言

コードが動くことと、保守し続けられることは別次元の話だ。

  • ハードコーディングを排除せよ: 検索クエリや対象レイヤー名は、必ず定数(`Const`)または外部設定ファイルから読み込むように設計すること。
  • 関数の分離: 「検索ロジック」と「抽出後のデータ処理ロジック」を分けること。これにより、将来的に「テキスト検索」から「カスタムプロパティ検索」へ仕様変更があった際も、検索エンジン部分だけを差し替えれば済むようになる。

Visio VBAは、書き手の習熟度がそのまま実行速度に直結する。`FindShapes`を使いこなすことは、単なる高速化ではない。「エンジンの挙動を支配する」という、プログラマとしての作法を身につけることと同義だ。

さあ、今すぐあなたのコードから無駄なループを消し去り、スマートな自動化ツールへと昇華させてほしい。何か疑問があれば、いつでも聞いてくれ。

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