【テクニカル・上級編】【上級プロ向け】図面内「部品表(BOM)」の構造解析:マルチレベルBOMの階層データをVBAで完全抽出してExcelへ出力 – SolidWorks VBA解析バイブル

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

階層を掌握せよ:図面内BOMの構造解析と高精度Excelインベントリ構築への極致

多くのエンジニアは、SolidWorks VBAを「単なる作業の自動化ツール」と考えている。しかし、我々プロフェッショナルにとって、それは「設計データの整合性を担保し、製造プロセスへと繋ぐデータパイプライン」の構築を意味する。

特に、図面(Drawing)内に配置された部品表(BOM)の抽出において、多くの開発者が陥る罠がある。それは、単に「テーブルの文字列を読み取る」という表層的なアプローチだ。マルチレベル(階層構造)を持つ複雑なアセンブリにおいて、単なるセル走査では、部品の親子関係、インデントによる階層表現、そしてデータの欠落を正しく処理することはできない。

本稿では、SolidWorks APIの深層に触れ、メモリ効率を極限まで高め、かつExcelへの出力速度を劇的に向上させる「プロフェッショナル仕様のBOM抽出アルゴリズム」を解説する。

1. アーキテクチャの設計思想:なぜ「セル走査」では足りないのか

図面上のBOMは、`TableAnnotation` オブジェクトとして存在する。しかし、我々が真に操作すべきは、その背後にある `BomTableAnnotation` だ。

一般的な初級者が書くコードは、`TableAnnotation.Text(row, col)` をループで回し、そのままExcelのセルに書き込む。これは、大規模なアセンブリ(数千パーツ)において、ExcelのCOMインターフェースへの過剰な呼び出しを引き起こし、処理速度を致命的に低下させる。

プロフェッショナルが採用すべき戦略:
1. メモリ内バッファリング: SolidWorksからデータを抽出する際は、直接Excelに書き込まず、一度「2次元のVariant配列」に全てのデータを格納する。
2. 階層ロジックの分離: BOMの「Level」列を解析し、インデント構造を論理的に再構築するロジックを、UI(Excel)の操作から完全に切り離す。
3. リソースの厳格な管理: `Set = Nothing` による明示的な解放はもちろん、COMオブジェクトのライフサイクルを意識し、メモリリークを徹底的に排除する。

2. 実装:高精度マルチレベルBOM抽出エンジン

以下に、図面内のBOMを解析し、階層情報を維持したままExcelへ高速転送する、実戦投入レベルのコードを示す。

Option Explicit

' ==============================================================================
' Module: BOM_Extractor_Pro
' Description: 図面内のBOMを解析し、階層構造を維持してExcelへ高速出力する
' Author: Legendary Chief Architect
' ==============================================================================

Sub ExportMultiLevelBOM()
    Dim swApp As SldWorks.SldWorks
    Dim swModel As SldWorks.ModelDoc2
    Dim swDraw As SldWorks.DrawingDoc
    Dim swSheet As SldWorks.Sheet
    Dim swView As SldWorks.View
    Dim swTable As SldWorks.TableAnnotation
    Dim swBomTable As SldWorks.BomTableAnnotation
    Dim xlApp As Object ' Excel.Application
    Dim xlWB As Object  ' Excel.Workbook
    Dim xlWS As Object  ' Excel.Worksheet
    
    ' 高速化のための変数
    Dim rowCount As Long, colCount As Long
    Dim r As Long, c As Long
    Dim dataBuffer() As Variant ' メモリ内バッファ(2次元配列)
    
    On Error GoTo ErrorHandler

    ' 1. SolidWorksへの接続とドキュメントの取得
    Set swApp = Application.SldWorks
    Set swModel = swApp.ActiveDoc
    
    If swModel Is Nothing Then
        MsgBox "SolidWorksドキュメントが開かれていません。", vbCritical
        Exit Sub
    End If
    
    If swModel.GetType <> swDocDRAWING Then
        MsgBox "図面ファイルを開いてください。", vbCritical
        Exit Sub
    End If
    
    Set swDraw = swModel
    
    ' 2. 図面内の最初のBOMテーブルを特定
    ' ※実務では、特定の名前のビューやテーブルを検索するロジックに拡張すること
    Set swView = swDraw.GetFirstView ' FirstViewはシート自体を指す
    Set swView = swView.GetNextView  ' 次のビュー(図面ビュー)へ
    
    Do While Not swView Is Nothing
        Set swTable = swView.GetFirstTableAnnotation
        Do While Not swTable Is Nothing
            ' BomTableAnnotationかどうかを判定
            If swTable.Type = swTableAnnotation_Bom Then
                Set swBomTable = swTable
                Exit Do
            End If
            Set swTable = swTable.GetNext
        Loop
        If Not swBomTable Is Nothing Then Exit Do
        Set swView = swView.GetNext
    Loop

    If swBomTable Is Nothing Then
        MsgBox "図面内にBOMが見つかりませんでした。", vbExclamation
        Exit Sub
    End If

    ' 3. データの解析とバッファリング
    ' テーブルのサイズを取得
    rowCount = swBomTable.RowCount
    colCount = swBomTable.ColumnCount
    
    ' 配列の再定義 (行, 列)
    ReDim dataBuffer(1 To rowCount, 1 To colCount)
    
    ' API呼び出し回数を最小化するため、一度に全データを配列へ格納
    For r = 1 To rowCount
        For c = 1 To colCount
            ' 文字列として取得
            dataBuffer(r, c) = swBomTable.Text(r - 1, c - 1)
        Next c
    Next r

    ' 4. Excelへの高速出力 (COMのオーバーヘッドを回避)
    Set xlApp = CreateObject("Excel.Application")
    xlApp.Visible = True
    Set xlWB = xlApp.Workbooks.Add
    Set xlWS = xlWB.Sheets(1)
    
    ' 配列を一度にセル範囲へ流し込む(これが最速のテクニック)
    ' Range(Cells, Cells) への一括代入は、セルごとの書き込みより数百倍高速
    xlWS.Range(xlWS.Cells(1, 1), xlWS.Cells(rowCount, colCount)).Value = dataBuffer
    
    ' 5. 階層構造の視覚的整形 (Post-Processing)
    ' Level列(仮に1列目とする)に基づいてインデントを適用
    Call ApplyHierarchyFormatting(xlWS, rowCount, colCount)

    MsgBox "BOMの抽出が完了しました。", vbInformation

CleanUp:
    ' 6. メモリの明示的解放 (重要)
    Set swBomTable = Nothing
    Set swTable = Nothing
    Set swView = Nothing
    Set swDraw = Nothing
    Set swModel = Nothing
    Set swApp = Nothing
    Set xlWS = Nothing
    Set xlWB = Nothing
    Set xlApp = Nothing
    Exit Sub

ErrorHandler:
    MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical
    Resume CleanUp
End Sub

' ------------------------------------------------------------------------------
' Sub: ApplyHierarchyFormatting
' Description: Excel上のLevel列に基づき、インデントと書式を制御する
' ------------------------------------------------------------------------------
Private Sub ApplyHierarchyFormatting(ws As Object, rows As Long, cols As Long)
    Dim r As Long
    Dim levelVal As Integer
    Dim indentSize As Integer
    
    ' 画面更新を停止して処理を加速
    ws.Application.ScreenUpdating = False
    
    For r = 2 To rows ' ヘッダーを除外
        ' Level列が1列目にあると仮定
        On Error Resume Next
        levelVal = CInt(ws.Cells(r, 1).Value)
        On Error GoTo 0
        
        If levelVal > 0 Then
            ' レベルに応じたインデント設定
            indentSize = (levelVal - 1) * 2
            ws.Cells(r, 2).IndentLevel = indentSize ' 部品名列(2列目)にインデント
            
            ' レベルに応じた色の変化(オプション)
            If levelVal = 1 Then
                ws.Rows(r).Font.Bold = True
            End If
        End If
    Next r
    
    ws.Application.ScreenUpdating = True
End Sub

3. 技術的深掘り:伝説的アーキテクトの知見

3.1. Variant配列による「一括書き込み」の魔力

コード内で `xlWS.Range(…).Value = dataBuffer` と記述している箇所に注目してほしい。これは単なるショートカットではない。
VBAにおいて、Excelのセル一つひとつに対して `Cells(r, c).Value = …` とアクセスすることは、プロセス間通信(IPC)を何度も発生させることを意味する。数千行のデータがある場合、この通信コストだけで数分を浪費する。
`Variant` 配列(メモリ上の連続した領域)を `Range` オブジェクトに一括で流し込む手法は、IPCの回数を「1回」に集約する。これが、プロフェッショナルとアマチュアを分かつ境界線だ。

3.2. オブジェクトのライフサイクルとメモリ管理

SolidWorksのような巨大なCOMサーバーを操作する場合、メモリ管理を怠ると、VBAエディタがフリーズしたり、SolidWorks自体がクラッシュしたりする。
`Set swBomTable = Nothing` のように、使用したオブジェクトを明示的に破棄することは、ガベージコレクション(GC)を待つのではなく、開発者がリソースの解放タイミングを完全に支配することを意味する。特にループ内でオブジェクトを生成する場合は、この原則を鉄の掟として守るべきである。

3.3. レガシー環境への配慮と拡張性

本コードでは `CreateObject(“Excel.Application”)` を使用している。これは、既にExcelが開いている環境でも、あるいは開いていない環境でも動作する堅牢な設計だ。
また、実務においては「Level列」が何列目にあるかは設計者によって異なる。これを定数(`Const COL_LEVEL As Integer = 1`)として定義し、外部設定ファイルや図面プロパティから動的に取得できるように拡張するのが、真のシステム管理者としての振る舞いである。

結論

BOM抽出の自動化は、単なる「作業の削減」ではない。それは、設計データの構造をデジタルツインとして正確に抽出し、後続の工程(ERP、MES、在庫管理)へと流し込むための「データの儀式」である。

APIの挙動を理解し、メモリとパフォーマンスを掌握したとき、君の書くコードは単なるスクリプトを超え、企業の基幹を支えるアーキテクチャへと昇華する。

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