AutoCAD VBAを掌握せよ:文字列一括置換に見る「堅牢なオブジェクト走査」の極意
AutoCADの自動化において、「図面内の文字列を一括置換する」というタスクは、一見すると初歩的な課題に見える。しかし、多くのエンジニアがこの「単純作業」でつまずき、大規模図面でフリーズさせたり、意図しないオブジェクトまで改変してツールを破綻させている。
なぜか? それは、AutoCADのオブジェクトモデルの構造を「単なる入れ物」としか見ていないからだ。
今回は、`AcadDocument`の深淵に触れ、`Find`メソッドに頼らず、かつメモリリークや意図せぬバグを排除した「プロフェッショナルな一括置換エンジン」の設計思想を伝授する。
—
1. なぜ「Findメソッド」に頼ってはいけないのか
AutoCAD VBAには `Find` メソッドが存在するが、あれはあくまでUI上での対話的な検索を補助するためのものだ。業務自動化ツールとして実装する場合、以下の理由で推奨しない。
- 制御の柔軟性欠如: 検索対象がTEXT、MTEXT、属性(ATTRIB)にまたがる場合、個別実装が必要になりコードが肥大化する。
- 例外処理の脆弱性: ブロック定義内のネストされた属性や、複雑なマルチテキスト(MTEXT)の内部コード(`\A1;`のようなフォーマットコード)の扱いが極めて困難。
- パフォーマンス: オブジェクトモデルのラッパーを介すため、数万要素を超える図面では処理が著しく遅延する。
我々エンジニアが目指すべきは、「SelectionSet」を活用し、型を厳密に判定しながら直接値を書き換えるアプローチである。
—
2. 堅牢な設計:文字列置換エンジンのアーキテクチャ
実務で使えるコードとは、「エラーが起きない」ことではなく、「エラーを予期して正しく制御できる」コードを指す。以下の設計指針を徹底せよ。
1. SelectionSetの即時解放: `Add`したSelectionSetsは必ず`Delete`で消去せよ。これを忘れるとAutoCADがメモリを食い潰し、他のアドインに悪影響を及ぼす。
2. 属性(ATTRIB)への配慮: 属性は「ブロック参照」の子供として存在する。図面内のすべての属性を走査するには、モデル空間だけでなく、ブロック定義の走査も視野に入れる必要がある。
3. パターンマッチングの抽象化: `Replace`関数をラップし、ワイルドカードや正規表現を柔軟に扱えるようにする。
—
3. 実装コード:一括置換のプロダクション・テンプレート
以下は、モデル空間内のテキスト系オブジェクトを一括で走査し、安全に置換を行うためのコードだ。
Option Explicit
‘ ———————————————————
‘ 図面内文字列一括置換メインプロシージャ
‘ ———————————————————
Public Sub BatchReplaceText(ByVal targetStr As String, ByVal replaceStr As String)
Dim ss As AcadSelectionSet
Dim ent As AcadEntity
Dim filterType(0) As Integer
Dim filterData(0) As Variant
‘ 1. セレクションセットの初期化(既に存在する場合は削除して再作成)
On Error Resume Next
ThisDrawing.SelectionSets.Item(“TextSearchSet”).Delete
On Error GoTo 0
Set ss = ThisDrawing.SelectionSets.Add(“TextSearchSet”)
‘ 2. 検索対象をTEXTおよびMTEXTに限定(属性は別ロジックが必要な場合が多い)
filterType(0) = 0
filterData(0) = “TEXT,MTEXT”
ss.Select acSelectionSetAll, , , filterType, filterData
‘ 3. オブジェクト走査
For Each ent In ss
If TypeOf ent Is AcadText Then
Dim txt As AcadText
Set txt = ent
If InStr(txt.TextString, targetStr) > 0 Then
txt.TextString = Replace(txt.TextString, targetStr, replaceStr)
txt.Update
End If
ElseIf TypeOf ent Is AcadMText Then
Dim mtxt As AcadMText
Set mtxt = ent
If InStr(mtxt.TextString, targetStr) > 0 Then
mtxt.TextString = Replace(mtxt.TextString, targetStr, replaceStr)
mtxt.Update
End If
End If
Next
‘ 4. 後処理:必ず解放する
ss.Delete
MsgBox “置換が完了しました。”
End Sub
—
4. 現場で生き残るための運用Tips
ブロック内の属性(ATTRIB)をどう扱うか?
上記のコードはモデル空間の「直下のオブジェクト」しか見ない。もしブロック参照内の属性まで置換したい場合は、`AcadBlockReference` の `GetAttributes` メソッドを呼び出し、配列として取り出した後にループを回すロジックを追記する必要がある。
データベース連携の罠
テキスト置換をExcelや外部DBのリストと同期させる場合、「置換前と置換後の組み合わせ」を辞書オブジェクト(`Scripting.Dictionary`)に格納して処理せよ。 1つのオブジェクトに対して何度も置換処理を繰り返すと、図面更新のオーバーヘッドが指数関数的に増大する。
パフォーマンスの極意
`Application.ScreenUpdating = False` に相当する機能はないが、`Application.SysVarChanged` を監視し、再描画の頻度を抑えることで、大規模図面での高速化が可能だ。
—
最後に:エンジニアとしての矜持
AutoCAD VBAはレガシーと言われることもある。しかし、CADの核心である「オブジェクトモデル」を理解していれば、これほど強力なツールはない。
今回紹介したコードはあくまで基礎だ。これをベースに、「置換履歴のログ出力」「処理対象レイヤーのフィルタリング」「Undoグループの作成(処理を一括で取り消せるようにする)」を実装してほしい。それこそが、ただのコード書きから、真の「業務自動化エンジニア」へと昇華する道だ。
現場の課題は、君のアーキテクチャで解決できる。さあ、コードを書こう。
