【入門編】【中級者向け】図面内の部品表(BOM)から指定したカスタムプロパティ列を抽出してCSV自動エクスポート – SolidWorks VBA解析バイブル

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

【極限の知見】BOMの迷宮を抜け出し、データを自在に操る:図面から特定プロパティをCSV出力する技術

こんにちは。設計自動化の世界へようこそ。

「マクロの記録」ボタンを押し、自分の操作を記録して、それを少し書き換える……。そんな段階から一歩踏み出そうとしているあなた。その向上心こそが、エンジニアとして最も重要な資質です。

今日、私たちが挑むのは「図面内のBOM(部品表)から、必要な情報だけを抜き出してCSVとして書き出す」というミッションです。

「そんなの、Excelにコピペすればいいじゃないか」と思うかもしれません。しかし、想像してみてください。毎日数十枚、数百枚と発行される図面から、重量や材質、仕入先情報を手作業で転記する苦行を。もし、ボタン一つでその作業が完了し、ERP(基幹システム)にそのまま投入できるデータが生成されたら?

それは単なる「時短」ではなく、「ヒューマンエラーというリスクの根絶」を意味します。

さあ、準備はいいですか? マクロの記録では決して到達できない、オブジェクトモデルの深淵へと共に潜っていきましょう。

1. 思考の地図:SolidWorks APIの階層構造を理解する

コードを書く前に、まず「脳内マップ」を整理しましょう。プログラミングにおいて、最も多い失敗は「今、自分がどのオブジェクトを触っているのか分からなくなること」です。

SolidWorksの図面におけるデータの持ち方は、以下のような入れ子構造(階層構造)になっています。

1. SldWorks (アプリケーション本体)

  • ModelDoc2 (開いている図面ファイル)
  • DrawingDoc (図面特有の機能を持つオブジェクト)
  • Sheet (シート)
  • View (配置された図面ビュー)
  • Annotation (注記・テーブルなどの注記オブジェクト)
  • BomTableAnnotation (BOMテーブル本体) ← ココが目的地!

ここで重要な知見を一つ。
BOMテーブルは、単なる「表」ではありません。SolidWorks APIの世界では「Annotation(注記)」の一種として扱われます。つまり、「図面上のどこかに配置された注記を探し、それがBOMテーブルであるかを確認する」というプロセスが必要になるのです。

2. プロの設計思想:なぜ「列番号」で指定してはいけないのか

ここからが、初級者と中級者を分ける決定的な違いです。

多くの初心者は、コードをこう書こうとします。
`CellValue = Table.Text(Row, 3)` (3列目の値を取る)

しかし、これは「極めて脆い(もろい)コード」です。
もし設計変更でBOMの左側に新しい列が追加されたら? その瞬間に、あなたのマクロは「材質」ではなく「全く関係のないデータ」を抽出してしまいます。

プロのエンジニアは、列番号ではなく「列の見出し名(ヘッダー名)」で列を特定します。
「『材質』という名前の列を探し、そのインデックス番号を特定してからデータを抜く」
この一工夫が、メンテナンス性の高い、真に信頼できる自動化ツールを生みます。

3. 実装:BOM抽出・CSVエクスポート・エンジン

それでは、魂を込めたコードを公開します。このコードは、図面内のすべてのシートを走査し、BOMテーブルを見つけたら、指定したヘッダー名(重量、材質など)の列を抽出してCSVに書き出します。

' ==============================================================================
' 目的: 図面内のBOMから特定のカスタムプロパティ列を抽出し、CSV出力する
' 設計思想: 列番号指定を排除し、ヘッダー名による動的列特定を行う
' ==============================================================================

Option Explicit

Sub ExportBOMToCSV()
    Dim swApp As SldWorks.SldWorks
    Dim swModel As SldWorks.ModelDoc2
    Dim swDraw As SldWorks.DrawingDoc
    Dim swSheet As SldWorks.Sheet
    Dim swAnn As SldWorks.Annotation
    Dim swTable As SldWorks.BomTableAnnotation
    Dim swTableAnn As SldWorks.TableAnnotation
    
    Dim vSheetNames As Variant
    Dim sheetName As Variant
    Dim targetHeaders As Variant
    Dim headerIdx As Variant
    Dim colIdx As Long
    Dim rowIdx As Long
    Dim colCount As Long
    Dim rowCount As Long
    
    Dim filePath As String
    Dim fileNum As Integer
    Dim csvLine As String
    Dim i As Integer
    
    ' --- 設定エリア ---
    ' 抽出したい列の名前をここに追加してください
    targetHeaders = Array("PART NO", "DESCRIPTION", "MATERIAL", "WEIGHT")
    ' 出力先ファイルパス(図面と同じフォルダに「BOM_Export.csv」として保存)
    ' ------------------

    Set swApp = Application.SldWorks
    Set swModel = swApp.ActiveDoc
    
    ' 図面が開かれているかチェック
    If swModel Is Nothing Or swModel.GetType <> swDocDRAWING Then
        MsgBox "図面ファイルを開いた状態で実行してください。", vbCritical
        Exit Sub
    End If
    
    Set swDraw = swModel
    filePath = swModel.GetPathName
    If filePath = "" Then
        MsgBox "ファイルを保存してから実行してください。", vbCritical
        Exit Sub
    End If
    ' パスをCSVファイル用に変換
    filePath = Left(filePath, InStrRev(filePath, "\")) & "BOM_Export.csv"
    
    ' ファイルオープン準備
    fileNum = FreeFile
    Open filePath For Output As #fileNum
    
    ' CSVのヘッダー行を書き込み
    csvLine = ""
    For i = LBound(targetHeaders) To UBound(targetHeaders)
        csvLine = csvLine & targetHeaders(i) & IIf(i = UBound(targetHeaders), "", ",")
    Next i
    Print #fileNum, csvLine

    ' 全シートをループ
    vSheetNames = swDraw.GetSheetNames
    For Each sheetName In vSheetNames
        swDraw.ActivateSheet CStr(sheetName)
        Set swSheet = swDraw.GetCurrentSheet
        
        ' シート内の注記(Annotation)を走査
        ' Note: Sheet内の全ての注記をチェックし、BOMテーブルを探す
        Dim swView As SldWorks.View
        Set swView = swDraw.GetFirstView ' Sheet自体を指す最初のビュー
        
        Do While Not swView Is Nothing
            Set swAnn = swView.GetFirstAnnotation2
            
            Do While Not swAnn Is Nothing
                ' 注記のタイプが「テーブル」であることを確認
                If swAnn.GetType = swAnnotationType_e.swTableAnnotation Then
                    ' テーブルをBomTableAnnotationとして扱う
                    Set swTable = swAnn.GetSpecificAnnotation
                    
                    ' それがBOMテーブルかどうかを判定(通常のテーブルと区別)
                    If Not swTable Is Nothing Then
                        Set swTableAnn = swTable
                        rowCount = swTableAnn.RowCount
                        colCount = swTableAnn.ColumnCount
                        
                        ' --- 列のインデックス特定プロセス ---
                        ' targetHeadersの各項目が、BOMの何列目にあるかを探す
                        Dim foundIndices() As Long
                        ReDim foundIndices(UBound(targetHeaders))
                        
                        For i = LBound(targetHeaders) To UBound(targetHeaders)
                            foundIndices(i) = -1 ' 初期値は「見つからない」
                            For colIdx = 0 To colCount - 1
                                ' ヘッダーのテキストを取得して比較
                                If Trim(swTableAnn.GetText(0, colIdx)) = targetHeaders(i) Then
                                    foundIndices(i) = colIdx
                                    Exit For
                                End If
                            Next colIdx
                        Next i
                        
                        ' --- データ抽出プロセス ---
                        ' 見つかった列のみ、行ごとにデータを抽出
                        For rowIdx = 1 To rowCount - 1 ' 0行目はヘッダーなので1から開始
                            csvLine = ""
                            For i = LBound(targetHeaders) To UBound(targetHeaders)
                                If foundIndices(i) <> -1 Then
                                    ' データの取得
                                    csvLine = csvLine & swTableAnn.Text(rowIdx, foundIndices(i))
                                Else
                                    ' 指定した列がBOMに存在しない場合は空文字
                                    csvLine = csvLine & ""
                                End If
                                ' カンマ区切り
                                If i < UBound(targetHeaders) Then csvLine = csvLine & ","
                            Next i
                            Print #fileNum, csvLine
                        Next rowIdx
                    End If
                End If
                Set swAnn = swAnn.GetNextAnnotation
            Loop
            Set swView = swView.GetNextView
        Loop
    Next sheetName

    Close #fileNum
    MsgBox "CSV出力が完了しました!" & vbCrLf & filePath, vbInformation
End Sub

4. 陥りやすい落とし穴と、回避するための「アーキテクトの視点」

このコードを動かす際に、あなたが直面するかもしれない壁について先に伝えておきます。

① 「見出しが一致しない」問題

コード内の `targetHeaders` に指定した文字列と、実際のBOMのヘッダーが1文字でも違う(あるいは余計なスペースがある)と、その列は無視されます。

  • 対策: `Trim()` 関数を使用して、前後にある不要なスペースを排除しています。また、大文字・小文字の違いにも注意してください。

② 「BOM以外のテーブル」を拾ってしまう問題

図面には、注記としての単なる「表(TableAnnotation)」も存在します。これらを誤って処理しようとするとエラーになります。

  • 対策: `swAnn.GetSpecificAnnotation` を使って、オブジェクトを `BomTableAnnotation` 型にキャスト(変換)するプロセスを挟んでいます。これにより、BOM特有の機能に安全にアクセスできます。

③ パフォーマンスの重み

図面内のすべてのビュー、すべての注記をループで回すのは、大規模な図面では時間がかかる場合があります。

  • アドバイス: もし速度が問題になる場合は、特定の「ビュー」だけに限定して走査する、あるいは `swApp.SetUserPreferenceIntegerValue` を使って画面更新を一時的に停止するなどの最適化を検討してください。

5. 最後に:自動化のその先へ

おめでとうございます。あなたは今、単なる「マクロの利用者」から、「業務プロセスを設計するエンジニア」へと進化しました。

今回作成したコードは、基礎ですが非常に強力な骨組みです。ここから、「特定の材質の部品だけを抽出する」「抽出した重量の合計値を計算して、図面のタイトルブロックに書き戻す」といった、さらに高度な機能へと拡張していくことができます。

SolidWorks VBAの世界は広大です。しかし、オブジェクトの階層を正しく理解し、堅牢なロジックを組み立てる技術さえあれば、どんな複雑な業務も必ず自動化できます。

ここをクリアすれば、SolidWorks VBAの基本はバッチリですよ。
さあ、次はどんな自動化に挑戦しますか? 応援しています。

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