こんにちは!AutoCADの自動化の世界へようこそ。
マクロの記録から一歩踏み出し、「実務で使える堅牢なツールを作りたい」と思い始めたあなたへ。
今回は、AutoCAD VBA中級者への登竜門であり、実務の現場で必ず直面するテーマ「ユーザーの自由奔放なクリックからプログラムを守る、堅牢な選択UIの構築法」を解説します。
ここをクリアすれば、あなたの書くVBAマクロは「機嫌を損ねるとすぐにエラーで止まるお騒がせツール」から、「ユーザーに優しく寄り添うプロフェッショナルなツール」へと生まれ変わります。一緒にマスターしていきましょう!
—
なぜ、素の `GetEntity` では実務で使えないのか?
AutoCAD VBAで画面上の図形をユーザーに選ばせる時、最も手軽なのが `AcadDocument.Utility.GetEntity` メソッドです。
まずは、よくある初学者のコードを見てみましょう。
Sub BadExample()
Dim ent As AcadEntity
Dim pt As Variant
‘ 画面から図形を1つ取得する
ThisDrawing.Utility.GetEntity ent, pt, “図形を選んでください: ”
‘ 選ばれた図形が「線分(Line)」かどうか判定したい
If TypeOf ent Is AcadLine Then
MsgBox “線分が選ばれました!”
Else
MsgBox “エラー:線分ではありません。”
End If
End Sub
このコード、一見すると動くように思えますよね。しかし、実務の現場では致命的な問題を抱えています。
1. 何も選ばずに画面の何もないところをクリック(またはESCキー)した瞬間、VBAが「オブジェクト変数が設定されていません」という冷酷なランタイムエラー(Error 458)で強制終了する。
2. 違う図形(文字や円など)が選ばれた場合、「エラーです」とメッセージを出してそのまま終了してしまう(ユーザーがもう一度選び直す機会を与えてくれない)。
イライラしたユーザーが「このマクロ、使えないな」とそっと閉じる音が聞こえてきませんか?
プロのエンジニアなら、ユーザーがどんな暴挙に出ようとも、優しく正道へと導く「ループ構造」と「エラーハンドリング」を実装しなければなりません。
—
解決策:Do〜LoopとTypeNameによる「お戻しなさい」UI
それでは、ユーザーが「正しい図形(今回は例として『線分:AcadLine』)」を選ぶまで、何度でも執拗に(しかし優しく)聞き返す、実務レベルの堅牢なコードを公開します。
以下のコードをVBAエディタ(VBE)の標準モジュールに貼り付けてみてください。
Sub GetLineRobustly()
Dim ent As AcadEntity
Dim pt As Variant
Dim targetSelected As Boolean
targetSelected = False
‘ 正しい図形が選ばれるまで無限ループを回す
Do While targetSelected = False
‘ 1. エラートラップの準備
‘ ユーザーがESCキーを押した場合などのランタイムエラーを捕捉する
On Error Resume Next
ThisDrawing.Utility.GetEntity ent, pt, vbCrLf & “【処理中】対象の『線分』をクリックしてください: ”
‘ エラーが発生した場合(ESCでの中断など)の処理
If Err.Number <> 0 Then
‘ エラー番号 13 (型が一致しません) やユーザーキャンセルを想定
MsgBox “選択がキャンセルされました。”, vbInformation, “終了”
On Error GoTo 0 ‘ エラートラップを解除
Exit Sub
End If
On Error GoTo 0 ‘ エラートラップを通常に戻す
‘ 2. オブジェクトが実際に取得されているかチェック(空振り対策)
If ent Is Nothing Then
MsgBox “図形が選択されませんでした。もう一度お願いします。”, vbExclamation, “再選択”
Else
‘ 3. オブジェクトの型を厳密に判定
‘ TypeOf … Is 演算子を使い、それがAcadLine(線分)かチェックする
If TypeOf ent Is AcadLine Then
targetSelected = True ‘ 条件クリア!ループを抜けるフラグを立てる
Else
‘ 違うものが選ばれた場合の優しいたしなめ
MsgBox “そこには「” & TypeName(ent) & “」が選ばれています。” & vbCrLf & _
“今回は【線分】を選んでください。”, vbExclamation, “種類が違います”
‘ メモリ解放の作法(次のループのために変数をクリア)
Set ent = Nothing
End If
End If
Loop
‘ — ここから先は、無事に線分が取れた後の処理 —
MsgBox “見事に線分が選択されました!” & vbCrLf & _
“オブジェクトハンドル: ” & ent.Handle, vbInformation, “成功”
‘ 後片付け
Set ent = Nothing
End Sub
—
コードの核心を解説する3つのポイント
ここをクリアすれば、AutoCAD VBAのオブジェクト操作の基本はバッチリです!コードの重要な3つの技術的背景を解説します。
1. `On Error Resume Next` による「ESC対策」
`GetEntity` 実行中にユーザーが `ESC` キーを押したり、右クリックメニューからキャンセルを選ぶと、VBAは実行時エラーを発生させてプログラムを強制終了させます。これを防ぐために、一時的にエラーを無視(`On Error Resume Next`)させ、`Err.Number` を監視して「あ、キャンセルしたんだな」と優しく離脱できるようにしています。
2. `ent Is Nothing` による「空振り対策」
図形オブジェクトの変数(`AcadEntity`)は、何も指していない状態を `Nothing` という特殊な状態として持っています。何もない空間をクリックした場合、`ent` は `Nothing` のまま次の行に進むため、判定を行わないと次の `TypeOf` でエラーになります。まずは「何か選ばれたか?」を `Is Nothing` で担保するのが鉄則です。
3. `TypeOf … Is` と `TypeName()` のコンボ
選ばれたものが何であるかを判定するのが `TypeOf ent Is AcadLine` です。
さらに、親切なことにエラーメッセージ内で `TypeName(ent)` を使って、「今あなたが選んだのは『AcadCircle(円)』や『AcadText(文字)』ですよ」と具体的に教えてあげることで、ユーザーの「何がダメだったの?」というストレスを劇的に軽減できます。
—
さらに高みを目指すあなたへ(チーフアーキテクトからの助言)
今回は「線分(AcadLine)」をターゲットにしましたが、実務では「線分またはポリラインのどちらでもOK」というケースも多々あります。
そんな時は、論理演算子を使って判定条件を拡張してみましょう。
If TypeOf ent Is AcadLine Or TypeOf ent Is AcadLWPolyline Then
‘ 線分か軽量ポリラインならOK!
targetSelected = True
End If
また、`GetEntity` ではなく、最初から特定の画層や図形タイプしか選べないように制限したい場合は、AutoCADの神髄である「SelectionSet(選択セット)」と「フィルター(FilterType / FilterData)」の技術領域へ進むことになります。これについては、また別の機会にお話ししましょう。
まずは今回紹介した 「Do〜Loop + 型チェック + キャンセル対策」 の基本形をあなたの引き出しにファイリングしてください。現場で必ずあなたを助けてくれる相棒のコードになるはずです。
それでは、快適なAutoCAD自動化ライフを!
