【入門編】【実務中級者向け】図面内の「特定ブロック」の有無で保存先を自動振り分け:属性情報を利用したフォルダ整理術 – AutoCAD VBA解析バイブル

スポンサーリンク
スポンサーリンク

【極限の知見】図面情報を「脳」に変える:属性情報による自動保存・フォルダ整理術

こんにちは。今日は、マクロの「記録」ボタンを卒業し、一歩上の「自動化エンジニア」へと踏み出したいあなたへ、実務で最も威力を発揮するテクニックを伝授します。

AutoCADを使っていると、こんな悩みにぶつかりませんか?
「図面を保存する時、プロジェクト番号をファイル名に入れて、決められたフォルダに移動させる作業が面倒すぎる……」
「手作業だと、どうしてもフォルダ名の間違いや、保存場所のミスが起きる……」

これ、実は「図面の中に既に答えがある」んです。

図面内のタイトルブロック(表題欄)に書き込まれた「工事番号」や「設計者名」といった属性情報(Attribute)をプログラムに読み取らせれば、AutoCADは自律的に考え、適切な場所に、適切な名前で自分自身を保存できるようになります。

今日は、そのための「設計思想」と「実装コード」を、魂を込めて解説します。

1. 思考のフレームワーク:オブジェクトの階層を辿る

プログラミング初学者が最初につまずくのは、「どうやってその情報に辿り着けばいいのか?」というルートの見失いです。

AutoCAD VBAの世界は、巨大なマンションのような階層構造になっています。属性情報を抜き出すには、以下のルートを正確に辿る必要があります。

1. ThisDrawing(この図面):今開いている図面そのもの
2. ModelSpace(モデル空間):図面が描かれている世界
3. BlockReference(ブロック参照):配置されている「タイトルブロック」という物体
4. Attributes(属性コレクション):ブロックの中に隠された「テキストデータ」の集まり

このルートを一つずつ、丁寧に、そして「もしそこにブロックがなかったら?」というリスクを想定しながら進むのが、プロの仕事です。

2. 実装コード:属性情報を読み取り、自動保存する

それでは、具体的なコードを見ていきましょう。このコードは、単なる「動くコード」ではありません。エラーを防ぎ、実務に耐えうる「堅牢なコード」を目指して書いています。

※事前にVBAエディタの `Tools` -> `References` から 「Microsoft Scripting Runtime」 にチェックを入れておいてください(フォルダ作成に必要です)。

Option Explicit

''' <summary>
''' 図面内の属性情報を取得し、プロジェクトフォルダへ自動保存する
''' </summary>
Sub SmartAutoSave()
    Dim acadApp As Object
    Dim doc As AcadDocument
    Set doc = ThisDrawing
    
    ' --- 設定エリア ---
    Const TARGET_BLOCK_NAME As String = "TITLE_BLOCK" ' 探したいブロックの名前
    Const TAG_PROJECT_NO As String = "PROJ_NO"       ' 工事番号のタグ名
    Const TAG_DESIGNER As String = "DESIGNER"        ' 設計者名のタグ名
    Dim ROOT_PATH As String
    ROOT_PATH = "C:\ProjectData\" ' 保存先のルートフォルダ
    ' ------------------

    Dim ent As AcadEntity
    Dim blockRef As AcadBlockReference
    Dim attrs As Variant
    Dim i As Integer
    
    Dim projNo As String: projNo = ""
    Dim designer As String: designer = ""
    Dim foundBlock As Boolean: foundBlock = False

    On Error GoTo ErrorHandler

    ' 1. モデル空間内を走査して、特定のブロックを探す
    For Each ent In doc.ModelSpace
        ' オブジェクトが「ブロック参照」かどうかを判定
        If TypeOf ent Is AcadBlockReference Then
            Set blockRef = ent
            
            ' ブロックの名前が一致するか確認
            ' ※動的ブロックの場合は Name ではなく EffectiveName を使うのがプロの技
            If blockRef.Name = TARGET_BLOCK_NAME Then
                foundBlock = True
                
                ' 2. ブロックに紐付く属性情報を取得
                attrs = blockRef.GetAttributes
                
                ' 属性リストをループして、目的のタグを探す
                For i = LBound(attrs) To UBound(attrs)
                    Select Case attrs(i).TagString
                        Case TAG_PROJECT_NO
                            projNo = attrs(i).TextString
                        Case TAG_DESIGNER
                            designer = attrs(i).TextString
                    End Select
                Next i
                
                ' 目的の情報を得られたらループを抜ける
                If projNo <> "" And designer <> "" Then Exit For
            End If
        End If
    Next ent

    ' 3. 情報が見つからなかった場合の処理
    If Not foundBlock Or projNo = "" Then
        MsgBox "エラー: タイトルブロック、または必要な属性情報が見つかりません。", vbCritical
        Exit Sub
    End If

    ' 4. 保存先フォルダの構築(FileSystemObjectを使用)
    Dim fso As New Scripting.FileSystemObject
    Dim targetFolder As String
    targetFolder = ROOT_PATH & projNo & "\"
    
    ' フォルダが存在しなければ作成する(再帰的に作成する処理が必要な場合は別途検討)
    If Not fso.FolderExists(targetFolder) Then
        fso.CreateFolder targetFolder
    End If

    ' 5. 新しいファイル名の作成と保存
    Dim newFileName As String
    newFileName = targetFolder & projNo & "_" & designer & ".dwg"

    ' 既にファイルが存在する場合の対策
    If fso.FileExists(newFileName) Then
        Dim res As VbMsgBoxResult
        res = MsgBox("同名のファイルが既に存在します。上書きしますか?", vbYesNo + vbQuestion)
        If res = vbNo Then Exit Sub
    End If

    ' 保存実行
    doc.SaveAs newFileName
    MsgBox "保存完了しました!" & vbCrLf & "場所: " & newFileName, vbInformation

    Exit Sub

ErrorHandler:
    MsgBox "予期せぬエラーが発生しました:" & vbCrLf & Err.Description, vbCritical
End Sub

3. ここが「プロ」の分かれ目:陥りやすい3つの罠

コードをコピペして動かすだけでは、あなたはまだエンジニアではありません。このコードの裏側にある「設計の意図」を理解してください。

① 「Name」と「EffectiveName」の罠

上記のコードでは `blockRef.Name` を使っています。しかし、もしそのブロックが「動的ブロック(Dynamic Block)」として操作されていた場合、AutoCAD内部では名前が `*U…` といった特殊な名前に書き換わってしまいます。
実務でより堅牢にするなら、`blockRef.EffectiveName` を使用するように設計してください。これが「仕様を理解しているエンジニア」の振る舞いです。

② オブジェクトのライフサイクルとエラーハンドリング

`For Each ent In doc.ModelSpace` でループを回している最中に、もし図面内のオブジェクトを削除したり変更したりすると、イテレータ(反復子)が壊れてエラーを吐きます。
今回は「読み取り」専用なので問題ありませんが、「図面を操作しながらループする」ときは、必ずオブジェクトの配列に一度格納してから処理する、という鉄則を覚えておいてください。

③ 属性(Attribute)のインデックスに頼らない

初心者は `attrs(0)`, `attrs(1)` のように番号で値を取ろうとしがちです。しかし、図面作成者が属性の並び順を入れ替えた瞬間、マクロはゴミデータを拾い、システムを破壊します。
必ず `TagString`(タグ名)を使って、「名前で指定して値を取り出す」ようにしてください。これが、変更に強いプログラムを作る唯一の方法です。

最後に:自動化の先にあるもの

このマクロを導入することで、あなたは「ファイルをどこに置いたっけ?」と探す時間や、「ファイル名がルール通りか?」と確認する時間をゼロにできます。

AutoCAD VBAを学ぶということは、単に作業を速くすることではありません。「人間がミスをしやすい領域を、機械に任せるためのルールを設計すること」なのです。

ここをクリアすれば、AutoCAD VBAの基本はバッチリですよ。
さあ、次はもっと複雑な、プロジェクト全体を管理するシステムへと挑戦していきましょう!応援しています。

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