【上級プロ向け】図面内「部品表(BOM)」の構造解析:マルチレベルBOMの階層データをVBAで完全抽出してExcelへ出力
「マクロの記録」を使って、なんとか自動化の第一歩を踏み出した。そんなあなたへ。
おめでとうございます。あなたは今、エンジニアリング自動化という果てしない旅の入り口に立っています。
しかし、実務の現場で求められるのは「記録された操作の再生」ではありません。
「アセンブリの構造が変わっても、瞬時に、正確に、階層構造を維持したままExcelへデータを出力する」といった、データの構造(ロジック)を理解した高度な自動化です。
今日は、SolidWorks VBAにおける最難関の一つであり、かつ最も価値の高いテーマの一つである「マルチレベルBOM(部品表)の階層抽出」について、その設計思想から実装コードまで、余すことなく伝授しましょう。
1. なぜ「マクロの記録」ではBOM抽出ができないのか?
多くの初心者が陥る罠があります。それは、「図面上のBOMテーブルを読み取ろうとする」ことです。
図面上のBOMテーブルは、あくまで「ある特定の視点」で表示された結果に過ぎません。
- 構成部品の階層が隠されている場合がある
- フィルタリングによって一部のデータが欠落している場合がある
- そもそもBOMテーブルが配置されていない図面もある
プロフェッショナルな自動化エンジニアが目指すべきは、図面(Drawing)を操作することではなく、アセンブリ(Assembly)のデータ構造そのもの(Component Tree)を直接走査(Traverse)することです。
アセンブリのツリー構造を「再帰的(Recursive)」に辿ることで、図面の表示状態に左右されない、完璧なインベントリリストを作成できるのです。
2. 核心となるアルゴリズム:再帰処理(Recursion)
マルチレベルBOMを抽出するための鍵は、「再帰処理」というプログラミング技法です。
想像してみてください。大きな箱(アセンブリ)の中に、中くらいの箱(サブアセンブリ)があり、その中に小さな箱(部品)が入っている構造を。
1. 箱を開ける。
2. 中身が「部品」なら、リストに書き込む。
3. 中身が「別の箱」なら、その箱に対して再び「1」の手順(自分自身を呼び出す)を実行する。
この「自分自身を呼び出す」仕組みが再帰です。これを使えば、階層が3層でも100層でも、同じロジックで無限に深く探索できます。
3. 実装コード:階層構造を維持したExcel出力
それでは、魂を込めて書いたコードを見ていきましょう。このコードは、現在開いているアセンブリを解析し、階層(インデント)を維持したままExcelへ書き出します。
' ==============================================================================
' プロジェクト名: Multi-Level BOM Extractor
' 概要: アセンブリの階層構造を再帰的に解析し、Excelへインデント付きで出力する
' 著者: Legendary Chief Architect
' ==============================================================================
Option Explicit
' Excel操作用の変数(グローバル管理)
Dim xlApp As Object
Dim xlWB As Object
Dim xlSheet As Object
Dim currentRow As Long
Sub Main()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssy As SldWorks.AssemblyDoc
Dim swConf As SldWorks.Configuration
Dim swRootComp As SldWorks.Component2
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 <> swDocASSEMBLY Then
MsgBox "アセンブリファイルを開いてください。", vbCritical
Exit Sub
End If
' 2. Excelの初期化
SetExcel
' ヘッダーの作成
xlSheet.Cells(1, 1).Value = "階層"
xlSheet.Cells(1, 2).Value = "部品番号 (Part Number)"
xlSheet.Cells(1, 3).Value = "部品名 (Description)"
xlSheet.Cells(1, 4).Value = "数量 (Quantity)"
xlSheet.Range("A1:D1").Font.Bold = True
currentRow = 2
' 3. アセンブリ構造の解析開始
Set swAssy = swModel
Set swConf = swModel.GetConfigurationByName(swModel.ConfigurationManager.ActiveConfiguration.Name)
Set swRootComp = swConf.GetRootComponent3(True)
' 再帰処理の開始(ルートコンポーネントから)
' 引数: コンポーネント, 現在の階層レベル
TraverseComponent swRootComp, 0
' 4. 後処理
xlSheet.Columns("A:D").AutoFit
MsgBox "BOMの抽出が完了しました。", vbInformation
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
End Sub
' ------------------------------------------------------------------------------
' 関数: TraverseComponent (再帰関数)
' 役割: コンポーネントを階層的に辿り、Excelに書き込む
' ------------------------------------------------------------------------------
Private Sub TraverseComponent(swComp As SldWorks.Component2, level As Integer)
Dim vChildren As Variant
Dim i As Long
Dim swChildComp As SldWorks.Component2
Dim swModelDoc As SldWorks.ModelDoc2
Dim partNo As String
Dim desc As String
' 子コンポーネントのリストを取得
vChildren = swComp.GetChildren
' 子コンポーネントがない場合は終了(末端の部品)
If IsEmpty(vChildren) Then Exit Sub
For i = 0 To UBound(vChildren)
Set swChildComp = vChildren(i)
' 抑制(Suppressed)されているコンポーネントはスキップ
If swChildComp.GetSuppression <> swComponentSuppressed Then
' コンポーネントの情報を取得
Set swModelDoc = swChildComp.GetModelDoc2
If Not swModelDoc Is Nothing Then
' プロパティから情報を取得(カスタムプロパティ名は環境に合わせて変更してください)
partNo = swChildComp.ReferencedConfiguration ' 簡易的に構成名を代用
desc = swModelDoc.GetCustomInfoValue("", "Description")
If desc = "" Then desc = "N/A"
Else
partNo = "未ロード"
desc = "N/A"
End If
' Excelへの書き込み
xlSheet.Cells(currentRow, 1).Value = String(level * 4, " ") & "|-- " ' インデント表現
xlSheet.Cells(currentRow, 2).Value = partNo
xlSheet.Cells(currentRow, 3).Value = desc
' ※ 数量のカウントは、実際には同一部品の出現回数を集計するロジックが必要
xlSheet.Cells(currentRow, 4).Value = 1
currentRow = currentRow + 1
' 【重要】再帰呼び出し:自分自身を呼び出して、さらに深い階層へ
TraverseComponent swChildComp, level + 1
End If
Next i
End Sub
' ------------------------------------------------------------------------------
' 関数: SetExcel
' 役割: Excelアプリケーションを起動し、ワークブックを準備する
' ------------------------------------------------------------------------------
Private Sub SetExcel()
On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")
If xlApp Is Nothing Then
Set xlApp = CreateObject("Excel.Application")
End If
On Error GoTo 0
xlApp.Visible = True
Set xlWB = xlApp.Workbooks.Add
Set xlSheet = xlWB.Sheets(1)
End Sub
4. コードの重要ポイント解説
このコードを理解するために、以下の3点を深く意識してください。
① 再帰呼び出しの設計 (`TraverseComponent`)
`TraverseComponent swChildComp, level + 1` という行が、このプログラムの心臓部です。
ここで自分自身を呼び出す際、`level + 1` を渡しています。これにより、「今、自分がどの深さにいるか」という情報を引き継ぎ、Excel上でのインデント(見た目の階層)を実現しています。
② オブジェクトのライフサイクルとNullチェック
`If swModelDoc Is Nothing Then` という判定を忘れてはいけません。
アセンブリ内の部品が「軽量化モード(Lightweight)」であったり、ロードされていない場合、`GetModelDoc2` は `Nothing` を返します。これを確認せずにプロパティにアクセスすると、即座に実行時エラーでプログラムが停止します。これはプロが最も気をつける「防御的プログラミング」の基本です。
③ Excel COMオートメーション
`CreateObject(“Excel.Application”)` を使用して、SolidWorksからExcelを操っています。
実務では、Excelを裏側で動かして高速化させる手法もありますが、まずは `xlApp.Visible = True` で、処理が進んでいる様子をユーザーに見せることが、使いやすいツールを作るコツです。
5. さらにステップアップするためのアドバイス
ここをクリアすれば、SolidWorks VBAの基本はバッチリですよ。しかし、真のプロフェッショナルを目指すなら、以下の課題に挑戦してみてください。
1. 数量の集計ロジック: 現状のコードは「1個」と出力していますが、アセンブリ内で同じ部品が複数ある場合、それらをカウントして集計するロジックを追加してみましょう。
2. カスタムプロパティの柔軟な取得: `GetCustomInfoValue` を使い、設計者が決めた特定のプロパティ(品番、材質、重量など)を自在に取得できるようにしましょう。
3. エラーハンドリングの強化: ネットワーク上のファイルが読み込めない場合や、Excelが編集モードになっている場合など、想定外の事態に備えた `Try-Catch` 的な処理を磨きましょう。
最後に
自動化の道は、単なる「楽をするための手段」ではありません。
「人間が本来集中すべき、創造的な設計業務に時間を戻すための、尊い投資」です。
一歩ずつ、確実に。コードの背後にある「構造」を理解していけば、あなたは必ず、SolidWorksを自由自在に操るマスターになれます。応援していますよ!
