Visio VBAの深淵:`HasCategory`による「図形の役割」の即時判定と堅牢な自動化設計
Visioの自動化において、多くのエンジニアが陥る「アンチパターン」がある。それは、`Shape.Name`や`Master.Name`に依存した文字列判定だ。
「この図形は組織図のメンバーだから…」「これはコンテナだから…」と名前で分岐を書くのは、UIの言語設定やユーザーによるマスタ名の変更で即座に崩壊する脆い設計だ。
本稿では、Visioのオブジェクトモデルを深く理解し、`Shape.HasCategory`メソッドを駆使して、「図形の本質的な役割(メタカテゴリ)」を型安全かつ高速に判定するプロフェッショナルな設計手法を伝授する。
—
1. なぜ「HasCategory」なのか:オブジェクトのライフサイクルを制御する
`HasCategory`は、Visio 2013以降に導入された、シェイプの役割を判定するための強力な武器だ。これは単なる名前の比較ではない。Visioエンジン内部のデータ構造に直接問いかけ、「そのシェイプが何として振る舞うべきか」という論理的なカテゴリーを検証する。
一般的なアンチパターンとの比較
- 名前判定: `If InStr(shp.Name, “Container”) > 0` → 崩壊リスク大。 ユーザーが図形をコピーして名前を変えれば終わり。
- HasCategory判定: `If shp.HasCategory(“Container”)` → 堅牢。 Visioの内部ルールに従うため、レイアウト操作やグループ化の影響を受けない。
—
2. 実践:保守性の高い自動分類エンジン
業務効率化ツールとして「図面内の特定カテゴリを抽出・処理する」ための、プロダクションレベルのコード例を示す。
Option Explicit
‘ ——————————————————————
‘ @brief 図面内の全シェイプから特定の役割(カテゴリ)を持つものを抽出・処理する
‘ @details 高速化のため、Shapeの走査は最小限に留め、エラーハンドリングを徹底する
‘ ——————————————————————
Public Sub ProcessShapesByCategory()
Dim vsoPage As Visio.Page
Dim vsoShape As Visio.Shape
Set vsoPage = ActivePage
‘ ページ内の全シェイプを走査
For Each vsoShape In vsoPage.Shapes
‘ 堅牢なエラーハンドリング: 削除されたシェイプ等による不意の停止を防ぐ
On Error Resume Next
‘ カテゴリによる分岐処理
‘ “Container”, “Callout”, “OrganizationChart” 等のカテゴリを識別
If vsoShape.HasCategory(“Container”) Then
Call ProcessContainer(vsoShape)
ElseIf vsoShape.HasCategory(“Callout”) Then
Call ProcessCallout(vsoShape)
ElseIf vsoShape.HasCategory(“OrganizationChart”) Then
Call ProcessOrgChart(vsoShape)
End If
On Error GoTo 0
Next vsoShape
End Sub
Private Sub ProcessContainer(ByVal shp As Visio.Shape)
‘ コンテナ内のシェイプを操作する際のロジックをここに記述
Debug.Print “Found Container: ” & shp.Name
End Sub
—
3. 現場で生き残るための「3つの極意」
① データベース連携のボトルネックを避ける
Visioのシェイプ情報をDB(SQL ServerやExcel等)へ書き出す際、`Shape.ID`と`Shape.UniqueID`(GUID)を混同してはならない。`ID`はページ内で一意だが、コピー&ペーストで再割り当てされる。永続的な紐付けが必要な場合は、必ず`UniqueID`を使用せよ。
② パフォーマンスを最大化する「レイヤー判定」の併用
`HasCategory`は非常に優秀だが、ページ内に数万のシェイプがある場合、すべての`HasCategory`を判定すると遅延が発生する。まず「レイヤー」や「親シェイプ(Group)」で範囲を絞り込み、その上で`HasCategory`を適用するのが、熟練エンジニアの流儀だ。
③ インターフェースとしての「カスタムプロパティ(Shape Data)」
`HasCategory`はあくまでVisioが定義した役割だ。自社固有の属性(例: 「重要度」「担当者」)を処理したい場合は、`HasCategory`で「対象の型」を絞り込んだ後、`Shape.CellsU(“Prop.xxxx”)`へアクセスしてデータを抽出・更新するハイブリッド設計を採用せよ。
—
結びに:なぜコードを「書く」のか
自動化ツールの価値は、コードの複雑さではなく「いかに保守コストを最小化できるか」にある。
`HasCategory`を用いた設計は、Visioの将来的なアップデートや、マスタ図形の変更に対しても極めて高い耐性を持つ。あなたが書いたそのロジックは、半年後のあなた自身や、後を引き継ぐエンジニアがデバッグに苦しむことなく動く「資産」でなければならない。
Visioのオブジェクトモデルを飼い慣らし、真に効率的な業務環境を構築してほしい。健闘を祈る。
