序文:なぜあなたのツールは「空振り」で死ぬのか
AutoCAD VBAの実務ツールにおいて、最もユーザーの不満が溜まるポイントはどこか。それは「操作の不備に対する脆弱性」だ。
`AcadDocument.Utility.GetEntity` メソッドは、ユーザーに図形を選択させる極めて基本的な関数だが、標準的な書き方では、ユーザーが図形のない空間をクリックした瞬間にランタイムエラーを吐いて停止する。あるいは、`On Error Resume Next` で強引に黙らせたとしても、その後の処理で `Nothing` を参照して結局クラッシュする。
これは「素人仕事」だ。プロが設計するツールは、ユーザーの「ミス」を「例外」として扱わない。「ミスは必ず起きるもの」として設計に組み込む。
今回は、実務の現場で絶対に避けて通れない、図形選択を「成功するまで、あるいは明確にキャンセルされるまで」繰り返す、堅牢なリトライ・ループの実装を伝授する。
—
1. 脆弱なコードと堅牢なコードの決定的な差
初心者は、単に `GetEntity` を呼び出す。中級者は `On Error` で囲む。だが、シニアアーキテクトは 「再試行のライフサイクル」 を設計する。
避けるべき「その場しのぎ」の例
‘ 非推奨:エラーが起きたら即終了、あるいは不安定な挙動
Dim ent As AcadEntity
Dim pt As Variant
On Error Resume Next
ThisDrawing.Utility.GetEntity ent, pt, “選択してください”
If ent Is Nothing Then Exit Sub ‘ 何も選ばれなかった時の処理が甘い
このコードでは、空クリック(空振り)と、ESCキーによるキャンセルを区別できない。また、一度失敗した後に再度入力を促す柔軟性もない。
—
2. 極限の堅牢性を備えたリトライ・ループの実装
実務でそのまま使える、洗練された関数を紹介する。この関数の肝は、「エラー番号の精査」と「ユーザーへのフィードバック」だ。
プロダクション・コード:`RobustSelectEntity`
”’
”’
”’ 選択されたオブジェクトを格納する変数
”’ (任意)特定のオブジェクト型のみ許可する(例: “AcDbLine”)
”’
Public Function RobustSelectEntity(ByRef selectedObj As AcadEntity, Optional ByVal filterType As String = “”) As Boolean
Dim pickPt As Variant
Dim retryFlag As Boolean
‘ 初期化
Set selectedObj = Nothing
RobustSelectEntity = False
Do
retryFlag = False
Err.Clear
On Error Resume Next
‘ 図形選択の実行
ThisDrawing.Utility.GetEntity selectedObj, pickPt, vbCrLf & “対象の図形を選択してください(キャンセルはESC): ”
‘ エラーハンドリングの要
If Err.Number <> 0 Then
‘ 2147352567 (0x80020009) 等は、空クリックやESC時に発生する
‘ Descriptionを確認し、キャンセルか空振りかを判定
If InStr(Err.Description, “キャンセル”) > 0 Or Err.Number = -2145320851 Then
‘ ユーザーが意図的にESCを押した場合
ThisDrawing.Utility.Prompt vbCrLf & “選択がキャンセルされました。”
Exit Function
Else
‘ 空振り(図形のない場所をクリック)の場合
ThisDrawing.Utility.Prompt vbCrLf & “図形が検出されませんでした。もう一度クリックしてください。”
retryFlag = True
End If
Else
‘ 図形は選択されたが、型チェックが必要な場合
If filterType <> “” Then
If selectedObj.ObjectName <> filterType Then
ThisDrawing.Utility.Prompt vbCrLf & “選択されたのは ” & selectedObj.ObjectName & ” です。 ” & filterType & ” を選択してください。”
Set selectedObj = Nothing
retryFlag = True
End If
End If
End If
On Error GoTo 0
Loop While retryFlag
If Not selectedObj Is Nothing Then RobustSelectEntity = True
End Function
—
3. アーキテクトが語る実装のポイント
① エラー番号 `-2145320851` の正体
AutoCAD VBAにおいて、`GetEntity` でESCキーが押された際、あるいは空振りの際の挙動は、環境やバージョンによって微妙に異なることがある。そのため、`Err.Number` だけでなく、`Err.Description` を確認するか、あるいは「エラーが出た=図形が取得できなかった」とシンプルに捉えた上で、ループを継続させる設計が最も安全だ。
② `filterType` による型の厳密な管理
実務では「線分だけを処理したい」「ポリラインだけを選ばせたい」というケースが殆どだ。この関数のように `ObjectName`(例: `AcDbLine`, `AcDbPolyline`, `AcDbBlockReference`)を判定基準に組み込むことで、後続の処理でキャストエラー(型不一致)が起きるリスクを根絶できる。
③ ユーザー体験(UX)の向上
空振りした際に何もメッセージを出さないツールは、ユーザーに「フリーズしたのか?」という不安を与える。`ThisDrawing.Utility.Prompt` を使い、コマンドラインに「何が起きたのか(空振りしたのか、型が違うのか)」を明示することは、プロフェッショナルなツールとしての最低限の礼儀である。
—
4. 外部データベースやファイル連携への応用
このリトライ・ループは、単体で完結するものではない。例えば、選択した図形のハンドル(Handle)をキーにして外部のデータベースやExcelから属性情報を引っ張ってくる場合、以下のようなガードレールを設置せよ。
1. ハンドルの永続性: 図形が選択されたら、即座に `selectedObj.Handle` を取得し、ログに記録する。
2. トランザクションの意識: 選択後の処理が重い(DB書き込み等)場合、リトライ・ループの中で安易にDB接続を開かないこと。選択が完了し、`RobustSelectEntity` が `True` を返してから接続を開始するのが鉄則だ。
—
結論:コードの堅牢性は、ユーザーへの敬意である
「正しく操作すれば動く」ツールは、まだベータ版だ。
「誤操作しても壊れず、正解へ導いてくれる」ツールこそが、現場で愛され、長く使われる。
今回紹介したリトライ・ループの構造は、`GetPoint` や `GetDistance` など、あらゆる対話型メソッドに応用できる。このロジックをあなたの標準ライブラリ(基盤クラス)に組み込み、二度と「空振りエラー」に怯えることのない開発環境を構築してほしい。
それが、AutoCAD VBAを掌握するということだ。
