【入門編】存在しないシェイプやプロパティを指定してしまった時の安全策:Visio VBAのエラーハンドリング完全版 – Visio VBA解析バイブル

スポンサーリンク

こんにちは。Visio VBAの世界へようこそ。
普段、マクロの記録から一歩踏み出し、自分だけの自動化ツールを作ろうと奮闘しているあなたの姿、素晴らしいですね。

しかし、Visio VBAの道を進むと必ずぶつかる「壁」があります。昨日まで動いていたコードが、図面上のシェイプを一つ消しただけで「実行時エラー ’91’: オブジェクト変数または With ブロック変数が設定されていません」と冷たく突き放してくる……そんな経験はありませんか?

Visioは非常に多機能な分、シェイプやプロパティ(シェイプデータ)の「存在」が非常に流動的です。今日は、そんな「予期せぬエラー」を優雅に回避し、プロ級の堅牢なコードを書くためのエラーハンドリングの極意を伝授します。

ここをマスターすれば、あなたのマクロは「壊れにくい、信頼されるツール」へと進化しますよ。

なぜVisio VBAは「エラー」が起きやすいのか?

通常のExcel VBAなどと違い、Visio特有の理由がいくつかあります。

1. IDの揮発性: シェイプを削除して作り直すと、見た目は同じでも内部の「ID」は変わります。
2. 名前の重複と消失: シェイプ名(例: “Process.10″)で指定していても、ユーザーがUI上で名前を変えてしまうことがあります。
3. シェイプデータの欠落: 「このシェイプには必ず『価格』というデータ項目があるはず」と思い込んでコードを書くと、その項目(セル)を持っていないシェイプに触れた瞬間にエラーになります。

これらを「プログラムのミス」と捉えるのではなく、「図面は常に変化するもの」という前提で備えるのが、一流のエンジニアの考え方です。

1. シェイプの存在を確認してから触る「安全な取得法」

まずは、特定のシェイプを操作する際の安全策です。いきなり変数に代入するのではなく、「そもそもそのシェイプ、今このページにいる?」を確認する習慣をつけましょう。

悪い例(すぐ止まる)

‘ もしID: 50 のシェイプが削除されていたら、ここでマクロが強制終了します
Set vsoShape = ActivePage.Shapes.ItemFromID(50)
vsoShape.Text = “Hello”

プロの書き方(安全策)

Visioには「ItemExists」のような便利なメソッドが標準で用意されていないため、エラーを逆手に取るか、ループで探すのが定石です。

”’

”’ 指定したIDのシェイプを安全に取得する関数
”’

Function GetShapeSafely(pg As Visio.Page, id As Long) As Visio.Shape
On Error Resume Next ‘ 一時的にエラーを無視
Set GetShapeSafely = pg.Shapes.ItemFromID(id)
On Error GoTo 0 ‘ エラー処理を元に戻す
End Function

‘ — 使い方 —
Sub Main()
Dim vsoShape As Visio.Shape
Set vsoShape = GetShapeSafely(ActivePage, 50)

If Not vsoShape Is Nothing Then
vsoShape.Text = “見つかりました!”
Else
MsgBox “シェイプが見つかりません。削除された可能性があります。”, vbExclamation
End If
End Sub

2. シェイプデータ(プロパティ)へのアクセスを鉄壁にする

Visio開発で最もエラーが多いのが、ShapeSheet(シェイプシート)のセルへのアクセスです。「シェイプデータ」にアクセスしようとして、その行(Row)が存在しない場合にエラーが発生します。

セルの存在チェックをルーチン化する

特定のプロパティ(例:`Prop.Cost`)を読み書きする前に、そのセルが存在するかどうかを確認する「ラッパー関数」を作っておくと、コードが劇的にスッキリします。

”’

”’ シェイプデータの値を安全に読み取る(存在しない場合は空文字を返す)
”’

Function GetShapeDataSafe(vsoShape As Visio.Shape, rowName As String) As String
‘ セルが存在するか確認 (VisExists は非常に強力なメソッドです)
‘ visExistsAnywhere = セルが存在するかどうかを判定
If vsoShape.CellExistsU(rowName, Visio.visExistsAnywhere) <> 0 Then
GetShapeDataSafe = vsoShape.CellsU(rowName).ResultStrU(Visio.visUnitCodes.visNoCast)
Else
GetShapeDataSafe = “” ‘ 存在しない場合はデフォルト値を返す
End If
End Function

Sub UpdatePrice()
Dim shp As Visio.Shape
Set shp = ActiveWindow.Selection(1) ‘ 選択中のシェイプ

‘ “Prop.Price” という項目がある時だけ処理する
Dim price As String
price = GetShapeDataSafe(shp, “Prop.Price”)

If price <> “” Then
Debug.Print “価格は ” & price & ” です。”
Else
Debug.Print “このシェイプには価格データがありません。”
End If
End Sub

3. マクロ全体を守る「最後の方舟」:グローバルエラーハンドラー

個別のチェックだけでなく、予期せぬ事態(メモリ不足やファイル破損など)に備えて、プロシージャ全体を包み込むエラーハンドリングを実装しましょう。

Sub MasterAutomation()
‘ エラーが起きたら「ErrorHandler」ラベルまでジャンプさせる
On Error GoTo ErrorHandler

Dim vsoApp As Visio.Application
Set vsoApp = Application

‘ — ここにメインの処理を書く —
Dim shp As Visio.Shape
Set shp = ActivePage.Shapes(1)
shp.Text = “処理中…”
‘ —————————-

‘ 正常終了した場合は、ここでマクロを抜ける
Exit Sub

ErrorHandler:
‘ エラーの内容をユーザーに優しく伝える
MsgBox “申し訳ありません、処理中にエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“内容: ” & Err.Description, vbCritical, “システムエラー”

‘ 必要に応じて後片付け処理をここに書く
End Sub

究極の知見:オブジェクトの「死」を意識する

Visio VBAを掌握するアーキテクトとして、一つだけ魂に刻んでおいてほしいことがあります。それは、「VBAの変数が持っているオブジェクト(ShapeやPage)は、ユーザーの操作一つで簡単に消滅する」ということです。

マクロの実行中に、ユーザーが手動でシェイプを消したり、ページを切り替えたりする可能性はゼロではありません。

  • 処理の直前で取得する: 変数に長く保持せず、使う直前に `Shapes.Item` などで取得し直す。
  • Nothingチェック: `If Not obj Is Nothing Then` を口癖にする。

この2点を意識するだけで、あなたの書くコードの堅牢性は、そこら辺のリファレンスを写しただけのコードとは比較にならないほど高まります。

まとめ

1. ItemFromID は直接使わない: ラッパー関数でラップして、`Nothing` かどうかをチェックする。
2. CellExistsU を使い倒す: セルにアクセスする前に、その「家(行)」があるか確認する。
3. エラーハンドラーは「お守り」: 予期せぬ停止を防ぎ、ユーザーに安心感を与える。

ここまでの内容を理解できれば、Visio VBAの基礎はもう完璧です。あなたはもう、ただ「記録されたコードを動かす人」ではなく、「堅牢なシステムを設計できる開発者」への第一歩を踏み出しました。

自信を持って、次の複雑な自動化にチャレンジしてくださいね。応援しています!

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