【実務・中級編】【上級プロフェッショナル】図面内のオブジェクトを、指定した条件(画層、色、線種、ブロック名など)で自動削除する安全な方法 – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAを掌握する:破壊的処理を「外科手術」に変えるオブジェクト削除の極意

AutoCADの自動化において、「オブジェクトを削除する」という処理は、一見単純に見えて最も牙を剥く危険なタスクだ。初心者が書くコードは、往々にして`SelectionSet`をループさせながらその場で`Delete`を叩く。

だが、待て。それは地雷原を散歩するようなものだ。

コレクションの要素をループ中に削除すれば、インデックスのズレが発生し、予期せぬオブジェクトが消えるか、例外エラーでツールがクラッシュする。本稿では、伝説的なエンジニアが現場で守っている「安全かつ高速なオブジェクト削除の作法」を伝授する。

1. なぜ「その場での削除」がタブーなのか

AutoCADのオブジェクトモデルにおいて、`SelectionSet`をループしながら`Delete`メソッドを呼び出すと、内部的なポインタの整合性が崩れることがある。特に、複雑なネスト構造やブロック参照が絡む場合、VBAの実行エンジンが「次に処理すべき対象」を見失うのだ。

真のプロフェッショナルは、決してループ内で削除しない。
「削除対象をリストアップするフェーズ」と「一括削除するフェーズ」を完全に分離する。これが、バグを未然に防ぐアーキテクチャの基本である。

2. 堅牢なオブジェクト削除のプロダクションコード

以下に、実務でそのまま使える、保守性と安全性を両立した削除エンジンのテンプレートを提示する。

Option Explicit

‘ ———————————————————
‘ 概要:条件に合致するオブジェクトを安全に削除するメイン処理
‘ ———————————————————
Public Sub BulkDeleteObjects()
Dim sset As AcadSelectionSet
Dim obj As AcadEntity
Dim targetList As Collection
Set targetList = New Collection

‘ 1. セレクションセットの初期化(既に存在する場合はクリア)
On Error Resume Next
ThisDrawing.SelectionSets.Item(“DeleteSet”).Delete
On Error GoTo 0
Set sset = ThisDrawing.SelectionSets.Add(“DeleteSet”)

‘ 2. フィルタリング(全画層の特定の条件を検索)
‘ 例:画層が”TMP_LAYER”であるオブジェクトを抽出
Dim gpCode(0) As Integer
Dim dataVal(0) As Variant
gpCode(0) = 8: dataVal(0) = “TMP_LAYER”

sset.Select acSelectionSetAll, , , gpCode, dataVal

‘ 3. 【重要】削除対象を一度メモリ上のコレクションに退避させる
‘ 理由:ループ中に削除するとインデックスがずれるため
For Each obj In sset
targetList.Add obj
Next

‘ 4. 安全な削除処理の実行
Dim msg As String
msg = targetList.Count & ” 個のオブジェクトを削除しますか?”
If MsgBox(msg, vbYesNo + vbExclamation, “確認”) = vbYes Then
Dim i As Long
For i = 1 To targetList.Count
‘ エラーハンドリングを入れ、Read-onlyやロック状態を回避
On Error Resume Next
targetList.Item(i).Delete
If Err.Number <> 0 Then
Debug.Print “削除失敗: ” & Err.Description
End If
On Error GoTo 0
Next i
ThisDrawing.Regen acActiveViewport
MsgBox “処理が完了しました。”
End If

sset.Delete
End Sub

3. なぜこの設計が「最強」なのか

① 二段階処理によるデカップリング

`SelectionSet`のループを直接回さず、`Collection`オブジェクトに退避させている。これにより、AutoCADの内部データベースに対する参照と、VBA側のリスト操作を切り離している。これにより、削除に伴うメモリ上の参照異常を100%回避できる。

② `On Error Resume Next` の戦略的利用

大規模図面では、画層がロックされていたり、外部参照(Xref)の一部であったりして、削除できないオブジェクトが混ざることがある。ここで処理を止めず、エラーを握りつぶしてログ(`Debug.Print`)に残すのが、業務を止めないための「大人の設計」だ。

③ クリーンアップの徹底

`SelectionSet`はAutoCADのメモリを消費する。処理終了後に`sset.Delete`で解放するのは、AutoCADという重厚なホストアプリケーションの上で動くプラグイン開発者としての最低限のたしなみである。

4. 業務自動化へのさらなる提言

このコードをベースに、以下の条件分岐を加えるとツールとしての完成度が飛躍的に高まる。

  • 画層フィルタの拡張: 複数の画層を対象にする場合、`FilterType`に論理演算(AND/OR)を組み込むか、あるいは`If`文でレイヤー名を判定するロジックを追加せよ。
  • Undoへの配慮: 削除処理が大規模になる場合、`ThisDrawing.StartUndoMark` と `EndUndoMark` で処理を囲むこと。これにより、誤操作時に「Ctrl+Z」一発で元の状態に完全復帰できる。

最後に:
コードは、書いた本人だけが理解できるものであってはならない。次にこのコードを保守する「未来の自分」や「後輩」のために、なぜそのロジックを選んだのか、コメントで意図を刻み込んでほしい。

AutoCAD VBAは古臭い技術だと言われがちだが、オブジェクトモデルの深淵を理解したエンジニアにとっては、これほどまでに強力な武器はない。さあ、安全なコードで、退屈な手作業を根絶しよう。

タイトルとURLをコピーしました