AutoCAD VBAを極める!画面非表示で属性情報を高速スクレイピングする究極テクニック
皆さん、こんにちは!AutoCAD VBAの世界へようこそ。伝説の業務自動化エンジニアがお届けする、この連載。今回は、AutoCAD VBAの基本中の基本から、画面描画のオーバーヘッドを極限まで削って、大量の図面から「属性情報」だけを高速に抜き出す、まさに「究極のテクニック」を伝授します。
マクロの記録だけでは物足りない、もっと効率的に作業を自動化したい、そんな意欲あふれる初学者の方々、そしてVBAの次のステップを目指すあなたへ。このページを読み終える頃には、AutoCAD VBAの基本がガッチリ掴め、現場でそのまま使えるコードのヒントまで手に入っているはずです。さあ、一緒にAutoCAD VBAの奥深い世界へ飛び込みましょう!
—
なぜ「画面非表示」で属性情報を高速抽出するのか?
日々の業務で、数百枚、数千枚といった大量の図面から部品構成表(BOM)のような属性情報を抜き出す作業に追われていませんか?一つ一つ図面を開いて、手作業で情報をコピー&ペースト…想像しただけでゾッとしますよね。
AutoCAD VBAを使えば、この地獄のような作業を劇的に効率化できます。特に、今回ご紹介する「画面非表示」での処理は、その中でもパフォーマンスを最大限に引き出すための肝となります。
考えてみてください。AutoCADで図面を開くとき、画面には複雑な図形が描画され、ユーザーインターフェース(UI)が表示されます。この「描画」や「UIの表示」には、実はかなりのリソースが使われているんです。
私たちがやりたいのは、あくまで「属性情報」というデータを取り出すこと。画面に描画される必要はまったくない。だからこそ、`AcadApplication.Visible = False` を使ってAutoCADの画面自体を非表示にしてしまうんです。これにより、描画処理やUIのレンダリングにかかる時間をカットし、本来の目的であるデータ抽出にリソースを集中させることができます。まさに、「見えないところで、仕事は速く進む」というわけです。
基礎の基礎:`AcadApplication` と `AcadDocument` オブジェクト
AutoCAD VBAを理解する上で、まず押さえておきたいのが、この二つのオブジェクトです。
- `AcadApplication` オブジェクト:
これは、AutoCADアプリケーションそのものを表すオブジェクトです。AutoCADを起動したり、終了させたり、画面の表示・非表示を切り替えたり、といったアプリケーション全体に関わる制御を行います。
まさに、AutoCADという「会社」の社長さんみたいな存在ですね。
- `AcadDocument` オブジェクト:
これは、現在開いている、あるいはこれから開く「図面ファイル」を表すオブジェクトです。図面内のオブジェクト(線、円、ブロックなど)にアクセスしたり、図面自体を保存・印刷したり、といった個別の図面ファイルに対する操作を行います。
こちらは、社長が指示を出す「個別のプロジェクト」や「部署」のようなイメージです。
これらのオブジェクトを介して、私たちはAutoCADに様々な指示を出していくことになります。
`AcadApplication.Visible = False` の魔法
さて、本題の「画面非表示」です。これは、`AcadApplication` オブジェクトの `Visible` プロパティを `False` に設定することで実現します。
‘ AutoCADアプリケーションオブジェクトを取得
Dim acadApp As AcadApplication
Set acadApp = GetObject(, “AutoCAD.Application”) ‘ 既に起動しているAutoCADを取得
‘ AutoCADの画面を非表示にする
acadApp.Visible = False
‘ ここで、画面描画を伴わないデータ抽出処理を実行する
‘ …
‘ 処理が終わったら、必要に応じて画面を再度表示する
‘ acadApp.Visible = True
ポイント:
- `GetObject(, “AutoCAD.Application”)`: 既に起動しているAutoCADアプリケーションのインスタンスを取得します。もしAutoCADが起動していない場合は、`Err.Number` でエラーを捕捉するか、`CreateObject(“AutoCAD.Application”)` を使う必要がありますが、今回は「大量の図面から」というシナリオなので、既に起動していることを前提とします。
- `acadApp.Visible = False`: これが魔法の呪文。画面が消えて、CPUやメモリにかかる描画負荷が激減します。
- `acadApp.Visible = True` (コメントアウト部分): 処理が終わった後、ユーザーに結果を見せたい場合などは、再度 `True` に戻して画面を表示させます。ただし、完全にバックグラウンドで処理を完結させる場合は、この行は不要です。
属性情報とは?そして、どうやって取り出す?
図面の中に配置された「ブロック」には、「属性情報(Attribute)」を持たせることができます。これは、部品番号、品名、数量などの情報を、図形とは別にデータとしてブロックに紐づける機能です。BOM作成には、この属性情報が欠かせません。
属性情報を取り出すには、まず図面内の「ブロック参照(Block Reference)」オブジェクトにアクセスし、そのブロック参照が持つ「属性(Attribute)」コレクションを調べます。
‘ AcadDocumentオブジェクトを取得 (例: 特定の図面ファイルを開く場合)
Dim acadDoc As AcadDocument
‘ Set acadDoc = acadApp.Documents.Open(“C:\path\to\your\drawing.dwg”)
‘ 図面内の全てのオブジェクトをループ処理
Dim obj As AcadObject
For Each obj In acadDoc.ModelSpace ‘ ModelSpace内のオブジェクトを対象とする場合
‘ オブジェクトがブロック参照かどうかを判定
If TypeOf obj Is AcadBlockReference Then
Dim blockRef As AcadBlockReference
Set blockRef = obj
‘ ブロック参照が属性を持っているか確認
If blockRef.HasAttributes Then
‘ 属性コレクションをループ処理
Dim attr As AcadAttribute
For Each attr In blockRef.Attributes
‘ 属性名と属性値を取得
Dim attributeName As String
Dim attributeValue As String
attributeName = attr.TagString ‘ 属性のタグ名 (例: “PART_NO”)
attributeValue = attr.TextString ‘ 属性の値 (例: “ABC-123”)
‘ ここで、取得した属性情報をリストやファイルに保存する
‘ 例: Debug.Print “タグ: ” & attributeName & “, 値: ” & attributeValue
‘ Call SaveAttributeData(attributeName, attributeValue)
Next attr
End If
End If
Next obj
コード解説:
1. `For Each obj In acadDoc.ModelSpace`: 図面内の「モデル空間」にある全てのオブジェクトを一つずつ取り出しています。他に「ペーパー空間」などもありますが、通常、属性情報はモデル空間に配置されます。
2. `If TypeOf obj Is AcadBlockReference Then`: 取り出したオブジェクトが「ブロック参照」であるかどうかを判定しています。
3. `If blockRef.HasAttributes Then`: そのブロック参照が「属性を持っているか」どうかを確認します。
4. `For Each attr In blockRef.Attributes`: 属性を持っている場合、そのブロック参照に紐づいている全ての属性を一つずつ取り出します。
5. `attr.TagString` と `attr.TextString`: それぞれ属性の「タグ名」(例:「部品番号」「品名」など、設定時に決めた名前)と、その「値」を取得します。ここが、私たちが欲しい情報そのものですね!
大量図面処理のための「ループ処理」と「エラーハンドリング」
数百枚、数千枚といった図面を処理するには、単一の図面を処理するコードを、複数の図面に対して繰り返し実行する必要があります。
1. 図面リストの準備:
まず、処理したい図面ファイルのパスがリストアップされたファイル(例: テキストファイル、Excelファイル)を用意します。
2. ファイルパスの読み込みとループ:
VBAでそのファイルからパスを読み込み、各パスに対して図面を開き、属性抽出処理を実行します。
‘ 処理対象の図面ファイルパスが記載されたテキストファイル
Const DRAWING_LIST_FILE As String = “C:\path\to\drawing_list.txt”
‘ 属性情報を保存するための配列やコレクションを宣言
Dim allAttributes As Collection
Set allAttributes = New Collection
‘ AutoCADアプリケーションオブジェクトを取得
Dim acadApp As AcadApplication
On Error Resume Next ‘ AutoCADが起動していない場合のエラーを無視
Set acadApp = GetObject(, “AutoCAD.Application”)
On Error GoTo 0 ‘ エラーハンドリングを元に戻す
If acadApp Is Nothing Then
MsgBox “AutoCADが起動していません。AutoCADを起動してください。”, vbExclamation
Exit Sub
End If
‘ AutoCADの画面を非表示にする (パフォーマンス向上のため)
acadApp.Visible = False
‘ 図面リストファイルを読み込む
Dim fileNum As Integer
fileNum = FreeFile ‘ 使用可能なファイル番号を取得
Open DRAWING_LIST_FILE For Input As fileNum
Dim drawingPath As String
Dim currentDoc As AcadDocument
Do While Not EOF(fileNum)
Line Input #fileNum, drawingPath ‘ 1行ずつ図面パスを読み込む
‘ 図面が開かれているかチェックし、開かれていなければ開く
Dim docFound As Boolean
docFound = False
Dim existingDoc As AcadDocument
For Each existingDoc In acadApp.Documents
If existingDoc.FullName = drawingPath Then
Set currentDoc = existingDoc
docFound = True
Exit For
End If
Next existingDoc
If Not docFound Then
On Error Resume Next ‘ ファイルが開けない場合のエラーを無視
Set currentDoc = acadApp.Documents.Open(drawingPath)
On Error GoTo 0 ‘ エラーハンドリングを元に戻す
If currentDoc Is Nothing Then
Debug.Print “エラー: 図面を開けませんでした – ” & drawingPath
GoTo NextDrawing ‘ 次の図面へスキップ
End If
End If
‘ — ここで属性抽出処理を呼び出す —
‘ 抽出した属性情報を allAttributes コレクションに追加する処理など
Call ExtractAttributesFromDocument(currentDoc, allAttributes)
‘ ————————————-
‘ 図面を閉じずに次の図面へ (バックグラウンド処理なので開いたままでも良い)
‘ もしメモリ節約のために閉じたい場合は以下のようにする
‘ currentDoc.Close SaveOptions:=acDoNotSaveChanges
‘ Set currentDoc = Nothing
NextDrawing:
Loop
Close fileNum ‘ ファイルを閉じる
‘ 処理完了後、必要なら画面を再表示
‘ acadApp.Visible = True
‘ 抽出した allAttributes コレクションを使ってBOMを作成する処理など
Call CreateBOM(allAttributes)
MsgBox “属性情報の抽出が完了しました!”, vbInformation
‘ — 属性抽出処理のサブルーチン —
Sub ExtractAttributesFromDocument(doc As AcadDocument, coll As Collection)
On Error Resume Next ‘ 属性処理中のエラーを無視
Dim obj As AcadObject
For Each obj In doc.ModelSpace
If TypeOf obj Is AcadBlockReference Then
Dim blockRef As AcadBlockReference
Set blockRef = obj
If blockRef.HasAttributes Then
Dim attr As AcadAttribute
For Each attr In blockRef.Attributes
‘ ここで、取得した属性情報を collection に保存する
‘ 例: Keyは図面パスと属性タグの組み合わせ、Valueは属性値
coll.Add attr.TextString, doc.FullName & “|” & attr.TagString
Next attr
End If
End If
Next obj
On Error GoTo 0
End Sub
‘ — BOM作成処理のサブルーチン (例) —
Sub CreateBOM(attributes As Collection)
‘ ここで、collection に蓄積された属性情報を使って
‘ CSVファイル出力やExcelへの書き込みなどを行う
‘ 例:
Dim outputFilePath As String
outputFilePath = “C:\path\to\bom_output.csv”
Dim fileNum As Integer
fileNum = FreeFile
Open outputFilePath For Output As fileNum
‘ ヘッダー行など(必要に応じて)
Print #fileNum, “Drawing Path,Attribute Tag,Attribute Value”
Dim key As Variant
Dim value As Variant
For Each value In attributes ‘ CollectionはValueでループするのが一般的
‘ Keyには “図面パス|属性タグ” の形式で保存されていると想定
Dim keyParts() As String
keyParts = Split(attributes.Key(attributes.Count), “|”) ‘ Keyはインデックスで取得
Dim drawingPath As String
Dim attributeTag As String
If UBound(keyParts) = 1 Then
drawingPath = keyParts(0)
attributeTag = keyParts(1)
Else
drawingPath = “Unknown”
attributeTag = “Unknown”
End If
Print #fileNum, Chr(34) & drawingPath & Chr(34) & “,” & _
Chr(34) & attributeTag & Chr(34) & “,” & _
Chr(34) & value & Chr(34)
Next value
Close fileNum
Debug.Print “BOMファイルを出力しました: ” & outputFilePath
End Sub
3. エラーハンドリングの重要性:
大量の図面を処理していると、様々なエラーに遭遇する可能性があります。
- 図面ファイルが見つからない
- 図面ファイルが破損している
- 特定の図面で処理が異常終了する
`On Error Resume Next` と `On Error GoTo 0` を適切に使い、エラーが発生しても処理が止まらず、次の図面に進むように工夫しましょう。エラーが発生した図面については、後で確認できるようにログに出力すると親切です。
陥りやすいエラーと、その回避策
- エラー1: AutoCADが起動していないのに `GetObject` を実行してしまう
- 原因: `GetObject` は既に起動しているアプリケーションを取得するため、AutoCADが起動していないとエラーになります。
- 回避策: `On Error Resume Next` を使い、`GetObject` の結果が `Nothing` であれば、`CreateObject` で起動するか、ユーザーに起動を促すメッセージを表示します。上記のコード例では、メッセージを表示して処理を中断する形にしています。
- エラー2: 存在しない図面パスを指定してしまう
- 原因: 図面リストのパスが間違っている、ファイルが移動・削除された。
- 回避策: `Documents.Open` メソッドでエラーが発生した場合を `On Error Resume Next` で捕捉し、エラーメッセージをログに出力して処理を続行します。
- エラー3: 特定のブロック参照や属性でエラーが発生する
- 原因: 図面データが予期しない形式だったり、特殊なオブジェクトが含まれている場合。
- 回避策: ブロック参照の属性をループ処理する部分(`ExtractAttributesFromDocument` サブルーチン内)にも `On Error Resume Next` を設定し、個別の属性処理でエラーが発生しても、他の属性や図面の処理を止めないようにします。
パフォーマンス向上のための追加TIPS
- `ScreenUpdating` の無効化: `Application.ScreenUpdating = False` をコードの最初に入れ、`Application.ScreenUpdating = True` でコードの最後に戻します。これにより、VBA実行中の画面のちらつきを防ぎ、描画負荷をさらに軽減できます。
- `DisplayAlerts` の無効化: `Application.DisplayAlerts = False` を設定すると、AutoCADからの警告ダイアログ(「保存しますか?」など)が表示されなくなり、処理が止まるのを防げます。処理終了後に `True` に戻すのを忘れずに。
- 不要なオブジェクトの解放: 処理が終わったオブジェクト変数(`AcadDocument`, `AcadBlockReference` など)は、`Set obj = Nothing` で明示的に解放すると、メモリ管理がより効率的になります。
まとめ:AutoCAD VBAマスターへの道
いかがでしたでしょうか?今回は、AutoCAD VBAの `AcadApplication` と `AcadDocument` オブジェクトを使い、`Visible = False` という強力なテクニックで画面描画のオーバーヘッドを極限まで削り、大量の図面から属性情報を高速にスクレイピングする手法を解説しました。
- `AcadApplication.Visible = False` でAutoCADをバックグラウンドで動かす。
- `AcadBlockReference` の `HasAttributes` プロパティと `Attributes` コレクションで属性情報にアクセスする。
- 大量の図面を処理するために、ファイルパスのリスト化とループ処理、そして堅牢なエラーハンドリングが不可欠。
これらの基礎をしっかりと理解し、今回ご紹介したコード例を参考に、ぜひご自身の業務に落とし込んでみてください。最初は少し戸惑うかもしれませんが、この「画面非表示」テクニックをマスターすれば、あなたのAutoCAD作業は劇的に効率化されるはずです。
ここをクリアすれば、AutoCAD VBAの基本はバッチリですよ! 次回も、さらに実用的で、あなたの業務を劇的に変えるようなテクニックをお届けします。お楽しみに!
