【入門編】【初心者】ステンシルを開かずにマスターシェイプの数だけを高速カウントする方法 – Visio VBA解析バイブル

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

Visio VBAを掌握する極限の知見:ステンシルを「開かずに」中身を覗く、軽量プロフェッショナルの流儀

こんにちは。自動化の世界へようこそ。

マクロの記録機能を使って「動くもの」を作れるようになった君は、すでに素晴らしい第一歩を踏み出しています。しかし、ここから先は「動けばいい」というフェーズから、「いかに美しく、速く、スマートに動かすか」という、真のエンジニアリングの領域へと足を踏み入れることになります。

今日、君に伝授するのは、Visio VBAにおける「リソース管理の極意」です。

具体的には、「ステンシル(Stencil)を開いてユーザーの画面をチカチカさせることなく、その中にマスターシェイプがいくつあるかを一瞬でカウントする方法」について。

「ステンシルの中身を知るには、まずステンシルを開かなければならない」……もし君がそう思っているなら、それは非常にもったいない。その思い込みを、今日ここで解き放ちましょう。

1. 初学者が陥る「重たい」コードの罠

まず、多くの初学者が書きがちな、いわゆる「マクロの記録」に近いコードを見てみましょう。

【避けるべき例】力任せのフルロード方式

Sub BadExample_CountMasters()
    Dim stencil As Visio.Document
    Dim count As Integer
    
    ' 1. ステンシルを物理的に開く(ここでユーザーの画面が動き、メモリを消費する)
    Set stencil = Visio.Documents.Open("C:\Templates\MyStencil.vssx")
    
    ' 2. マスターを一つずつ数える(あるいは単にCountプロパティを見る)
    count = stencil.Masters.Count
    
    MsgBox "マスターの数は " & count & " 個です。"
    
    ' 3. 使い終わったら閉じる
    stencil.Close
End Sub

なぜこれが「プロ」の仕事ではないのか?

このコードには、3つの大きな問題(コスト)が潜んでいます。

1. UI(ユーザーインターフェース)の負荷: `Documents.Open` を実行すると、Visioはステンシルを画面上に描画しようとします。ユーザーが作業している最中に、突然別のウィンドウが開くのは非常に不親切です。
2. メモリの浪費: ステンシルには、大量の画像データや複雑な定義が含まれていることがあります。それらをすべてメモリ上に展開(ロード)するのは、単に「数を知りたいだけ」にしては、あまりに重すぎるのです。
3. 実行速度の低下: ファイルを開き、描画し、そして閉じる。この一連のプロセスは、コンピュータにとって非常に「重い」作業です。

2. アーキテクトの思考:オブジェクトのライフサイクルを制御する

プロのエンジニアは、「目的のために必要な最小限のリソースしか使わない」という原則を持っています。

今回の目的は「マスターの数を知ること」です。
ならば、「ユーザーには見えない、極めて短い時間だけ、バックグラウンドでこっそり読み込んで、数を確認したら即座に消え去る」というアプローチをとるべきです。

これを実現するために、我々は2つの武器を使います。

  • `Application.ScreenUpdating = False`: 画面の更新を停止し、ユーザーの目に余計な動きを見せない。
  • 厳格なエラーハンドリング: ファイルが存在しない場合にプログラムがクラッシュするのを防ぐ。

3. 【実践】軽量・高速マスターカウント・メソッド

さあ、魂を込めて書いた、実戦投入可能なコードを提示します。これをコピーして、君のプロジェクトの基盤にしてください。

''' <summary>
''' ステンシルをユーザーの画面を動かさずに開き、マスターシェイプの数を返します。
''' </summary>
''' <param name="stencilPath">ステンシルファイルのフルパス</param>
''' <returns>マスターの数。ファイルが見つからない場合は -1 を返します。</returns>
Function GetMasterCountLightweight(ByVal stencilPath As String) As Long
    Dim stencilDoc As Visio.Document
    Dim masterCount As Long
    
    ' --- 準備フェーズ ---
    ' 画面更新を停止(これによって「開いた感」を消し、高速化する)
    Application.ScreenUpdating = False
    
    ' エラーハンドリングの開始
    ' ファイルが存在しない、あるいは使用中などの予期せぬエラーで止まらないようにする
    On Error GoTo ErrorHandler

    ' --- 実行フェーズ ---
    ' 1. ステンシルをバックグラウンドで開く
    ' ※ 実際にはメモリにロードされるが、ScreenUpdating=Falseにより描画コストを最小化する
    Set stencilDoc = Visio.Documents.OpenEx(stencilPath, visOpenDocked)
    
    ' 2. マスターの数を取得(プロパティへのアクセスは非常に高速)
    masterCount = stencilDoc.Masters.Count
    
    ' 3. 使い終わったらすぐに閉じる(オブジェクトのライフサイクルを完結させる)
    ' visCloseSave ensures we don't accidentally prompt to save changes
    stencilDoc.Close
    Set stencilDoc = Nothing

    ' 成功時の戻り値
    GetMasterCountLightweight = masterCount
    
    ' --- 後処理フェーズ ---
CleanUp:
    ' 画面更新を必ず元に戻す(これを忘れるとVisioの挙動がおかしくなる!)
    Application.ScreenUpdating = True
    Exit Function

ErrorHandler:
    ' エラーが発生した場合(ファイルパス間違いなど)
    Debug.Print "Error in GetMasterCountLightweight: " & Err.Description
    GetMasterCountLightweight = -1 ' エラーを示す特別な値
    
    ' 失敗しても必ず後処理へ飛ばす
    Resume CleanUp
End Function

''' <summary>
''' テスト用のメインルーチン
''' </summary>
Sub TestMasterCount()
    Dim path As String
    Dim count As Long
    
    ' テストしたいステンシルのパスを指定してください
    path = "C:\Users\Public\Documents\MyCustomStencil.vssx"
    
    count = GetMasterCountLightweight(path)
    
    If count >= 0 Then
        MsgBox "成功!マスターの数は " & count & " 個です。", vbInformation
    Else
        MsgBox "エラー:ステンシルを開けませんでした。パスを確認してください。", vbCritical
    End If
End Sub

4. ここがプロの分かれ道:解説とポイント

このコードをただ使うだけでなく、なぜこう書いたのかを理解してください。ここをクリアすれば、君はもう初学者ではありません。

① `OpenEx` と `visOpenDocked` の選択

通常の `Open` ではなく、`OpenEx` を検討する価値があります。引数に `visOpenDocked` を指定することで、ステンシルをドキュメントとして「開く」のではなく、ステンシルパネルの一部として「接続」する挙動を制御できます。これにより、メインの図面への干渉を最小限に抑えられます。

② `Application.ScreenUpdating = False` の重要性

これは単なる「見た目の問題」ではありません。Visioが「画面に図形を描画するための計算」を行うプロセスをスキップさせるため、実行速度そのものが劇的に向上します。

③ エラーハンドリングと `CleanUp`

エンジニアが最も恐れるのは、プログラムが途中で止まり、`ScreenUpdating = False` のままになってしまうことです。そうなると、ユーザーは「Visioが固まった!」とパニックになります。
`On Error GoTo ErrorHandler` と `Resume CleanUp` を組み合わせることで、たとえエラーが起きても必ず画面更新を元に戻すという、堅牢な設計(ロバストネス)を実現しています。

④ オブジェクトの解放 (`Set = Nothing`)

`Set stencilDoc = Nothing` と書くことで、メモリ上の参照を明示的にクリアします。これは、大規模な自動化ツールを作る際に、メモリリーク(メモリの使いすぎによる動作不安定)を防ぐための鉄則です。

最後に

「ただ動くコード」を書くのは簡単です。しかし、「ユーザーに優しく、コンピュータに負荷をかけず、エラーにも強いコード」を書くには、一歩踏み込んだ思考が必要です。

今日学んだ「オブジェクトのライフサイクルをコントロールする」という考え方は、Visio VBAだけでなく、あらゆるプログラミング言語に応用できる普遍的な知恵です。

君の書くコードが、より洗練されたものになることを期待しています。
さあ、次の課題へ進みましょう!

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