【AutoCAD VBA実践】GetIntegerで「個数」を安全に取得する:実務で通用する堅牢な入力バリデーションの極意
業務自動化エンジニアの私たちが、現場で最も恐れるもの何か。それは、コードのバグそのものではない。「ユーザーの自由奔放な操作」である。
AutoCAD VBAでマクロを開発する際、`AcadDocument.Utility.GetInteger` メソッドは、ユーザーから「個数」や「繰り返し回数」といった整数値を取得するための基本中の基本だ。しかし、このメソッドを「教科書通り」に実装しているようでは、プロのエンジニアとは言えない。
何も考えずに `GetInteger` を呼び出すコードを書くことは、時限爆弾を抱えて現場に爆弾をばら撒くようなものだ。
今回は、ユーザーが平然と行う「キャンセル(Escキー連打)」や「文字列の入力」といった暴挙に対し、プログラムが微動だにせず、かつ優しくエスコートするための「プロダクション品質の入力バリデーション設計」を伝授する。
—
1. なぜ「素の `GetInteger`」は実務で使い物にならないのか?
まずは、世にはびこる「やってはいけないアンチパターン」を見てみよう。
‘ 【悪夢のアンチパターン】絶対に書いてはいけないコード
Sub BadGetIntegerExample()
Dim acadApp As AcadApplication
Dim count As Integer
Set acadApp = ThisDrawing.Application
‘ ユーザーに個数を尋ねる
count = ThisDrawing.Utility.GetInteger(“配置する個数を入力してください: “)
‘ ここに後続処理が続く…
MsgBox count & ” 個配置します。”
End Sub
このコードの何が問題か。
ユーザーがプロンプトに対して [Esc] キーを押した瞬間、または右クリックでキャンセルした瞬間、AutoCADは容赦なく実行時エラー(エラー番号:-2147352567 / 自動化エラー)を発生させ、マクロは強制終了する。
エラーハンドリング(`On Error`)が記述されていないため、CAD画面は中途半端な状態のまま放置され、エンドユーザーは「このマクロ、壊れてるんだけど」と不満を募らせる。これが、現場で使えないツールが生まれる瞬間だ。
プロのエンジニアであれば、「ユーザーは必ずキャンセルするものだ」「あり得ない数値を入力するものだ」という性悪説に基づいた設計を行わなければならない。
—
2. 堅牢な入力取得の3大原則
実務で耐えうる入力ロジックを構築するには、以下の3つを担保する必要がある。
1. エラーハンドリングによるキャセールの完全捕捉:
`GetInteger` 中の [Esc] キー押下は、VBAのランタイムエラーとして飛んでくるため、これをトラップして「正常な中断」として処理する。
2. ドメインロジックに基づく数値の範囲チェック(バリデーション):
「個数」や「回数」なのだから、`0` 以下や、業務上あり得ない巨大な数値(例: 10,000個など)は弾く必要がある。
3. ループ構造による再入可能性(リトライ):
不正な値が入力された場合、最初からマクロをやり直させるのではなく、「正しい値が入力されるまでプロンプトを繰り返す」のがUI/UXの鉄則である。
—
3. 【コピペOK】プロダクションコード実装例
それでは、上記の原則をすべて満たした、実務でそのまま使える堅牢な関数を提示しよう。このパターンをあなたのライブラリに組み込んでほしい。
‘ ==============================================================================
‘ モジュール名: ModUtilityValidation
‘ 概要: AutoCADのユーティリティを通じた安全な整数値取得ラッパー
‘ ==============================================================================
Public Sub RunBatchPlacement()
Dim targetCount As Integer
‘ 安全なラッパー関数経由で個数を取得する
If TryGetValidInteger(“配置する個数を入力してください (1-100): “, 1, 100, targetCount) Then
‘ — 正常系の処理 —
MsgBox targetCount & ” 個のオブジェクトを処理します。”, vbInformation, “処理開始”
‘ ここに実際の自動化ロジック(ループやデータベース連携など)を記述
Else
‘ — キャンセルまたは異常終了時の処理 —
MsgBox “処理がキャンセルされました。”, vbInformation, “中断”
End If
End Sub
‘ ——————————————————————————
‘ 目的: キャンセル判定と値の範囲チェックを内包した安全な整数取得関数
‘ 戻り値: Boolean (True: 有効な値を取得, False: ユーザーによるキャンセル)
‘ ——————————————————————————
Private Function TryGetValidInteger(ByVal promptMessage As String, _
ByVal minValue As Integer, _
ByVal maxValue As Integer, _
ByRef outValue As Integer) As Boolean
Dim util As AcadUtility
Set util = ThisDrawing.Utility
Do
‘ エラーハンドリングの有効化(Escキー対策)
On Error GoTo ErrorHandler
‘ ユーザーからの入力を受け取る
outValue = util.GetInteger(vbCrLf & promptMessage)
‘ エラー監視を解除
On Error GoTo 0
‘ ドメインバリデーション(範囲チェック)
If outValue >= minValue And outValue <= maxValue Then
TryGetValidInteger = True
Exit Function
Else
MsgBox "入力値は " & minValue & " から " & maxValue & " の間で指定してください。", _
vbExclamation, "入力エラー"
' ループを継続して再入力を促す
End If
Loop
Exit Function
ErrorHandler:
' Err.Number = -2147352567 (Automation error) またはユーザー起因のエラーを捕捉
' AutoCADのUtilityメソッドでEscが押された場合、通常 Err.Number が発生する
If Err.Number <> 0 Then
‘ エラーをクリアしてキャンセル(False)を返す
Err.Clear
TryGetValidInteger = False
Exit Function
End If
End Function
—
4. チーフアーキテクトが解説するコードの急所
このコードがなぜ優れているのか、アーキテクトの視点から構造的な解説を加える。
ライフサイクルとスコープの分離
`AcadUtility` オブジェクトへの参照は、毎回 `ThisDrawing.Utility` を叩くのではなく、ループに入る手前でローカル変数にキャッシュしている。大した差ではないように思えるが、COMオブジェクトへのアクセスオーバーヘッドを最小限に抑えることは、大規模な図面を扱うAutoCAD VBAにおいて極めて重要なパフォーマンス・ハックである。
`Do…Loop` によるリトライデザイン
ユーザーが `150` や `-5` といった無効な値を入力した際、プログラムがそこで終わるのではなく、`MsgBox` で警告を出したのちに再び `GetInteger` の入力待ちへシームレスに戻る。この「ユーザーを迷子にさせない設計」が、業務ツールの品質を劇的に向上させる。
`On Error` のスコープ管理
VBAのエラーハンドリングは非常にプリミティブ(関数単位でのジャンプ)であるため、`GetInteger` を呼び出すピンポイントの区間だけに `On Error GoTo ErrorHandler` を挟み込んでいる。さらに、正常終了時には即座に `On Error GoTo 0` でデフォルト挙動に戻すことで、予期せぬバグの隠蔽を防いでいる。
—
5. まとめと実務への展開
AutoCAD VBAにおけるユーザーインタラクションは、Webアプリケーションにおけるフォームバリデーションと同じ熱量で設計されなければならない。
今回紹介した `TryGetValidInteger` パターンをマスターすれば、`GetInteger` だけでなく、実数値を扱う `GetReal` や、座標を扱う `GetPoint` の入力バリデーションにもそのまま応用が可能だ。
「動けばいいコード」から「壊れないコード」へ。
あなたの書くマクロの信頼性を高め、社内のCADオペレーターたちから「あの人が作ったツールは使いやすい」と言わしめるエンジニアを目指してほしい。
