【実務・中級編】【中級】マスターシェイプの「動作」をVBAで動的に割り当てる – Visio VBA解析バイブル

スポンサーリンク
スポンサーリンク

Visioを「お絵描きツール」から「業務アプリケーション」へ昇華させる:マスターシェイプへの動的動作割り当て戦略

多くのエンジニアがVisio VBAに手を出すが、そのほとんどが「図形を自動で並べる」という低次元な自動化で止まっている。しかし、真に価値のある業務ツールとは、「図形そのものが機能(ロジック)を保持し、ユーザーの操作に反応して業務プロセスを駆動させる」ものである。

例えば、ステンシルから「承認ノード」を配置し、それをダブルクリックすれば、即座に外部データベースから承認経路を読み込み、ダイアログを表示する。あるいは、特定のシェイプを右クリックして「データ連携」を選択すれば、そのシェイプが持つ属性値に基づいてAPIリクエストを飛ばす。

これを実現するために、多くの凡庸な開発者が陥る罠がある。それは、`ActiveWindow.Selection` を監視し、巨大な `If…ElseIf` や `Select Case` で「今どの図形が選ばれているか」を判定する泥臭い実装だ。

断言する。その設計は破綻している。

図形が増えるたびにコードを修正し、シェイプの名前を変更した瞬間にバグが多発する。保守性の地獄へようこそ。

本記事では、世界最高峰の設計思想に基づいた「行動ディスパッチャ・パターン」を用いた、堅牢で拡張性の高い動作割り当て手法を伝授する。

1. アーキテクチャ設計:静的な図形に「DNA」を組み込む

プロの設計では、VBA側に「どの図形が何をするか」を書かない。代わりに、マスターシェイプの「User-defined Cells(ユーザー定義セル)」に、実行すべき関数名やアクションIDをメタデータとして保持させる。

設計コンセプト

1. マスターシェイプ(DNA): `User.ActionName` というセルに、実行したいVBA関数名を文字列で保持させる。
2. ディスパッチャ(神経系): ユーザーイベント(ダブルクリック等)を捕捉し、シェイプのメタデータを読み取り、該当する関数へ動的にルーティングする。
3. アクションモジュール(筋肉): 個別の機能ロジックを独立した関数として定義する。

これにより、新しい機能を追加したい場合は「マスターシェイプに新しい関数名を書き込み、VBAに関数を一つ追加する」だけで完結する。既存のイベントハンドラを一切触る必要はない。

2. 実装:プロダクショングレードのコード例

以下に、ダブルクリックイベントをトリガーとして、マスターシェイプに定義されたアクションを動的に実行する実装例を示す。

ステップ1:マスターシェイプの準備

ステンシルのマスターシェイプを右クリック $\rightarrow$ [シェイプデータ] または [ShapeSheet] を開き、`User` セクションに `ActionName` という名前のセルを作成し、値に `ExecuteApprovalProcess` などの関数名を記入しておくこと。

ステップ2:VBA実装

' ==============================================================================
' Module: Mod_BehaviorDispatcher
' Description: シェイプのメタデータに基づき、動作を動的に割り当てるディスパッチャ
' ==============================================================================
Option Explicit

' 動作を定義するインターフェース的な役割を果たす関数
' Visioのイベントから呼ばれ、適切なアクションへルーティングする
Public Sub DispatchShapeAction(ByVal targetShape As Visio.Shape)
    On Error GoTo ErrorHandler

    If targetShape Is Nothing Then Exit Sub

    ' 1. マスターシェイプまたはインスタンスからアクション名を取得
    ' User-defined cell "ActionName" を参照する
    Dim actionName As String
    actionName = GetActionName(targetShape)

    If actionName = "" Then
        Debug.Print "No action defined for shape: " & targetShape.Name
        Exit Sub
    End If

    ' 2. CallByNameを用いて、標準モジュール等に定義された関数を動的に実行
    ' ここでは簡略化のため、Select Caseによるルーティングを行うが、
    ' より高度な実装ではクラスモジュールを用いたコマンドパターンを推奨する。
    ExecuteAction actionName, targetShape

    Exit Sub

ErrorHandler:
    MsgBox "Action Execution Error: " & Err.Description, vbCritical, "System Error"
End Sub

' ユーザー定義セルからアクション名を取得するヘルパー関数
Private Function GetActionName(ByVal shp As Visio.Shape) As String
    On Error Resume Next
    ' ShapeSheetのUserセクションからActionNameセルを取得
    GetActionName = shp.CellsU("User.ActionName").Formula
    ' 式形式(= "ActionName")で格納されているため、ダブルクォーテーションを除去
    GetActionName = Replace(GetActionName, """", "")
    On Error GoTo 0
End Function

' アクション名に基づいて実際のロジックを呼び出す
Private Sub ExecuteAction(ByVal actionName As String, ByVal shp As Visio.Shape)
    Select Case actionName
        Case "ExecuteApprovalProcess"
            Call Action_ApprovalProcess(shp)
        Case "SyncWithDatabase"
            Call Action_SyncDatabase(shp)
        Case "OpenDetailProperty"
            Call Action_OpenDetails(shp)
        Case Else
            MsgBox "未定義のアクションです: " & actionName, vbExclamation
    End Select
End Sub

' ==============================================================================
' Module: Mod_Actions
' Description: 個別のビジネスロジックを記述するモジュール
' ==============================================================================

Public Sub Action_ApprovalProcess(ByVal shp As Visio.Shape)
    ' ここに承認プロセスのロジックを記述
    MsgBox "シェイプ [" & shp.Name & "] の承認プロセスを開始します。", vbInformation
    ' 例: DB接続 -> 承認者リスト取得 -> ダイアログ表示
End Sub

Public Sub Action_SyncDatabase(ByVal shp As Visio.Shape)
    ' ここにDB連携ロジックを記述
    MsgBox "データベースと同期中...", vbInformation
End Sub

Public Sub Action_OpenDetails(ByVal shp As Visio.Shape)
    MsgBox "詳細プロパティを表示します。", vbInformation
End Sub

ステップ3:イベントの紐付け(重要)

Visio VBAには標準的な「Shape_DoubleClick」イベントが存在しない(Documentレベルで捕捉する必要がある)。
最も堅牢な方法は、ShapeSheetの `EventDblClick` セルに、VBAの関数を呼び出す式を書き込むことだ。

ShapeSheet設定:
`EventDblClick` $\rightarrow$ `=CALL(“DispatchShapeAction”, TheShape)`
※ `TheShape` は自分自身を指す予約語である。

3. チーフアーキテクトが教える「落とし穴」と回避策

この設計を実務に投入する際、素人が見落とし、プロが徹底的に管理するポイントが3つある。

① ステンシルの読み取り専用問題

マスターシェイプをVBAで動的に書き換えようとすると、ステンシルが読み取り専用(Read-only)である場合に実行時エラーが発生する。
対策: マスターを直接書き換えるのではなく、配置した後の「インスタンスシェイプ」のセルを操作するか、ステンシルを一度 `Document.Open` で書き込み権限付きで開き、変更後に保存せずに閉じる戦略をとれ。

② パフォーマンスの重み(ShapeSheetの評価コスト)

大量のシェイプが配置された状態で、すべてのシェイプに複雑な数式を埋め込むと、再計算コストが増大し、描画がカクつく。
対策: `EventDblClick` のようなイベント駆動型であれば問題ないが、`User-defined Cell` の値を頻繁に参照するループ処理を書く場合は、`Shape.CellsU` へのアクセス回数を最小限に抑え、変数にキャッシュせよ。

③ 外部データベース連携のトランザクション管理

シェイプからDBを叩く際、ループ内で接続・切断を繰り返すのは最悪のアンチパターンだ。
対策:

  • Connection Poolの擬似的な実装: グローバル変数またはシングルトンクラスでDB接続を保持し、セッションを使い回せ。
  • 非同期的な処理の検討: 重い処理はVBAで待たせず、外部のexeやスクリプトに引数を渡してキックし、完了通知を待つ設計にせよ。

4. まとめ:真の自動化とは何か

単に「コードが動く」ことと、「システムとして運用できる」ことの間には深い溝がある。

今回提示した「メタデータによる動作割り当て」は、コードとデータを分離する設計思想である。これにより、VBAに詳しくない管理者がステンシル上の値を書き換えるだけで、ツールの挙動を制御することが可能になる。

「コードを書き換えずに挙動を変えられる設計」。これこそが、プロフェッショナルが到達すべき極限の自動化である。

さあ、今すぐその泥臭い `If…ElseIf` を捨て、アーキテクチャに基づいた設計に移行せよ。

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