AutoCAD VBAを掌握する極限の知見:`GetDistance`のキーワード入力併用術
AutoCAD VBAの限界は、どこにあるのか。
多くの初学者は、フォームから数値を入力させたり、固定されたプロンプトのやり取りだけで満足する。しかし、実務で求められるのは、プロ仕様の「標準コマンドに肉薄するインタラクティブ性」だ。
ユーザが図面上で距離を指定する際、単に数値や点を入力させるだけでなく、コマンドラインから `S` などのキーワードを受け付け、設定画面(UserForm)を呼び出す――。これを実現するのが `AcadDocument.Utility.GetDistance` メソッドのキーワード機能である。
本稿では、この高度な対話型インターフェースの実装法を、オブジェクトのライフサイクルと実務的耐性を考慮した「チーフアーキテクトの知見」とともに徹底解説する。
—
1. `GetDistance` メソッドの深層とキーワード制御のメカニズム
`GetDistance` は単なる数値取得関数ではない。AutoCADのトランザクションおよび入力サブシステムと密接に連携し、グラフィックス画面上のベクトルを計算する強力なAPIだ。
このメソッドのシグネチャと挙動の本質を理解している者は少ない。
引数として「基準点」と「プロンプトメッセージ」を取るが、事前に `InitializeGet` メソッドを組み合わせることで、数値以外の「キーワード(文字列)」の割り込み入力を受け付けることが可能になる。
レガシー環境と実務における罠
AutoCAD VBAはシングルスレッドのランタイムであり、モーダル/非モーダルフォームの制御や、CADのエディタ状態(ActiveDocumentのロック状態)を誤ると、致命的なクラッシュ(いわゆる致命的なエラーによる強制終了)を引き起こす。
特に、図面上のインタラクション中にUserFormをポップアップさせる場合、AutoCADのフォーカスとVBAフォームのフォーカスの奪い合いを制御する必要がある。
—
2. 実装コード:プロ仕様の対話型距離取得ルーチン
以下のコードは、`GetDistance` を実行中にユーザーが `[S]ettings` キーワードを入力すると、専用の設定用UserFormを呼び出し、設定変更後に処理をシームレスに再開する実用的なモジュールである。
Option Explicit
‘ メインエントリーポイント:標準コマンド同等の操作感を持つ距離取得
Public Sub GetDistanceWithKeywords()
Dim acadDoc As AcadDocument
Set acadDoc = ThisDrawing.Application.ActiveDocument
On Error GoTo ErrorHandler
Dim basePoint As Variant
Dim dist As Double
Dim userKeyword As String
‘ 1. ループ構造により、設定変更後の再入力を可能にする
Do
‘ キーワードの初期化 (Bit 1: ゼロを許可しない, Bit 2: 負数を許可しない などの制御も可能)
‘ ここではキーワード “Settings” (短縮形 “S”) を登録
acadDoc.Utility.InitializeGet litKeyword, “Settings S”
‘ プロンプトの設定(キーワードの選択肢を明示する)
Dim promptMsg As String
promptMsg & vbCr & “距離を指定するか、[設定(S)]を変更してください: ”
‘ 2. 基準点の取得(今回は原点を仮の基準点とするが、動的に指定させることも可能)
basePoint = acadDoc.Utility.GetPoint(, “基準点を指定してください: “)
‘ 3. GetDistanceの実行とキーワード判定
On Error Resume Next
dist = acadDoc.Utility.GetDistance(basePoint, promptMsg)
If Err.Number <> 0 Then
‘ エラーが発生した場合、それがキーワード入力によるものか判定
If Err.Number = -2147352567 Or Err.Description Like “キーワード” Then
‘ キーワード取得時のエラー番号をトラップし、入力されたキーワードを取得
userKeyword = acadDoc.Utility.GetInput()
If UCase(userKeyword) = “SETTINGS” Or UCase(userKeyword) = “S” Then
‘ 4. 設定用UserFormの呼び出し
Call ShowSettingsForm
‘ 設定変更後、ループの先頭に戻り再入力を促す
Err.Clear
GoTo ContinueLoop
End If
Else
‘ ユーザーによるキャンセル(ESCキーなど)のハンドリング
Dim errNum As Long
errNum = Err.Number
On Error GoTo ErrorHandler
If errNum = -2147467259 Then ‘ User cancelled
MsgBox “操作がキャンセルされました。”, vbInformation
Exit Sub
Else
Err.Raise errNum
End If
End If
Else
‘ 正常に距離が取得できた場合
On Error GoTo ErrorHandler
Exit Do
End If
ContinueLoop:
Loop
‘ 成功時の処理
MsgBox “取得された距離: ” & Format(dist, “0.0000”), vbInformation, “完了”
CleanUp:
‘ オブジェクトの明示的解放によるメモリ最適化
Set acadDoc = Nothing
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “致命的エラー”
Resume CleanUp
End Sub
‘ 設定画面を安全に呼び出すためのラッパー
Private Sub ShowSettingsForm()
Dim frm As Object
‘ 動的インスタンス化により、メモリリークと参照の肥大化を防ぐ
Set frm = New frmSettings
‘ モーダル表示(AutoCADのメインウィンドウを親とする)
frm.Show vbModal
‘ 即座にアンロードしてメモリ解放
Unload frm
Set frm = Nothing
End Sub
—
3. チーフアーキテクトが指摘する「極限の知見」
上記のコードは単に動くだけではない。実務の現場で生き残るためのアーキテクチャ上の工夫が組み込まれている。
① エラー番号 `-2147352567` の罠と `GetInput()` の同期
AutoCAD VBAにおいて、`GetDistance` や `GetPoint` の実行中にユーザーがキーワードを入力すると、VBAランタイムはエラーを発生させる。この仕様は極めてレガシーであり、直感的ではない。
エラーが発生した瞬間に `Err.Number` を捕捉し、速やかに `AcadDocument.Utility.GetInput()` を呼び出してバッファから文字列を回収しなければ、入力ストリームが破損する。このシーケンスの厳密な同期こそが、安定稼働の鍵となる。
② オブジェクトライフサイクルの徹底管理
`ThisDrawing.Application.ActiveDocument` のようなルートオブジェクトへの参照をローカル変数に保持し、処理の終了時には必ず `Set acadDoc = Nothing` を実行する。
VBAのガベージコレクションは頼りにならない。特に図面の開閉や長時間のバッチ処理を行う環境では、COMコンポーネントの参照解放漏れがメモリリーク(VBA領域の肥大化・AutoCAD自体の不安定化)直結する。
③ フォームの「都度生成・即座破棄」パターン
UserFormをグローバル変数や `Unload` せずに隠す(`Hide`)実装を見かけるが、これは悪手である。
CADアドインとしてのVBAは、長期間起動しっぱなしになることが多い。フォーム内のコントロール群や画像リソースがメモリ上に残り続けることを防ぐため、必ず `New` で生成し、用が済んだら `Unload` して `Nothing` を代入するライフサイクルを厳守すべきだ。
—
総括
AutoCAD VBAで高度なアドインを構築することは、もはや過去の技術の遺物を触ることではない。限られたリソースとレガシーなAPIの仕様を極限まで理解し、鉄壁の堅牢性を持たせること――それこそが、シニアエンジニアに求められる真のスキルセットである。
この `GetDistance` のキーワード制御をマスターすれば、あなたの書くVBAマクロは、単なる「お助けスクリプト」から、商業用アドインに匹敵する「プロフェッショナル・ツール」へと昇華するだろう。
