【テクニカル・上級編】【中級者向け】部品表(BOM:Bill of Materials)の図面内自動配置と列幅・並び順の完全制御 – SolidWorks VBA解析バイブル

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

BOM制御の覇権:図面自動化における「決定論的」なテーブル操作の極意

図面自動化の領域において、多くのエンジニアが「とりあえずBOM(部品表)が表示される」レベルで満足し、その先にある「制御」の壁に突き当たって挫折する。

アセンブリ図面におけるBOMは、単なるデータの羅列ではない。それは設計意図、製造要件、そしてサプライチェーンへの指示書が凝縮された、図面内における最も動的かつ重要な「情報構造体」である。列の並び順が一つ違うだけで、製造現場の誤認を招き、システム間連携におけるデータ整合性を破壊する。

本稿では、単なる「BOMの挿入」といった初歩的な解説は一切排除する。シニアエンジニアが直面する、「テンプレートの変更に耐えうる堅牢な列制御」、「メモリリークを許さないオブジェクトのライフサイクル管理」、そして「描画更新コストを最小化するパフォーマンス最適化」に焦点を当て、実務における極限の知見を伝授する。

1. オブジェクト・ライフサイクルの厳格な管理

SolidWorks VBAにおいて、最も忌避すべきは「不完全なオブジェクト解放」である。特に、図面(Drawing)とアセンブリ(Assembly)を跨ぐ操作を行う際、参照カウントが適切に管理されていないと、SolidWorksのプロセスがメモリ上に澱(おり)のように残り、大量の図面をバッチ処理する際に不可避なクラッシュを引き起こす。

`Set swBomTable = Nothing` を書くのは当然だが、真に重要なのは、「どの階層のオブジェクトを、どのタイミングで解放するか」という設計思想だ。

' 破滅的なメモリリークを防ぐための基本原則
' 1. 階層の深いオブジェクトから順に、明示的にNothingを代入する
' 2. Error Handler内で必ず解放処理を通す
' 3. ループ内でのオブジェクト生成は最小限に留める

2. 決定論的アプローチ:インデックス依存からの脱却

初級者が書くコードは、`Column(1)`、`Column(2)` のように列インデックスを直接指定する。これは、設計者がテンプレートの列を一つ追加した瞬間に、システム全体を崩壊させる「時限爆弾」となる。

プロフェッショナルが採用すべきは、「プロパティ名(またはヘッダー文字列)による探索」である。BOMの各列が保持するプロパティ名を走査し、目的の列を特定するロジックを組み込むことで、テンプレートの変更に対して自己修復的な堅牢性を確保する。

3. 実装:BOM完全制御エンジン

以下に、実務レベルで耐えうるBOM制御のコア・モジュールを示す。このコードは、BOMの挿入、特定のカスタムプロパティに基づく列の再配置、不要な列の非表示化、および列幅の最適化を一気通貫で行う。

Option Explicit

''' <summary>
''' 図面内のBOMを高度に制御するメインルーチン
''' </summary>
Public Sub ExecuteAdvancedBomControl()
    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 swBomTable As SldWorks.BomTableAnnotation
    Dim swTable As SldWorks.TableAnnotation
    
    On Error GoTo ErrorHandler

    ' 1. SolidWorksへの接続とドキュメントの検証
    Set swApp = Application.SldWorks
    Set swModel = swApp.ActiveDoc
    
    If swModel Is Nothing Then Exit Sub
    If swModel.GetType <> swDocDRAWING Then
        MsgBox "図面ファイルを開いてください。", vbCritical
        Exit Sub
    End If
    
    Set swDraw = swModel
    Set swSheet = swDraw.GetCurrentSheet
    
    ' 2. 描画更新の停止(パフォーマンス最適化の要)
    ' 大規模アセンブリでは、描画更新を抑制することで処理速度が数倍変わる
    swModel.LockGraphics = True 

    ' 3. BOMの挿入(既存のBOMがある場合は取得、なければ挿入)
    ' ここでは簡略化のため、最初のビューにBOMを挿入するロジックとする
    Set swView = swDraw.GetFirstView ' Sheet自体が最初のビュー
    Set swView = swView.GetNextView  ' 最初のモデルビュー
    
    If swView Is Nothing Then GoTo CleanUp

    ' BOMの挿入 (InsertBomTable3)
    ' 引数は構成、配置、配置形式など。実務ではテンプレート指定が肝
    Dim bomConfig As String
    bomConfig = swModel.GetConfigurationNames(0) ' アクティブな構成を使用
    
    ' BOM挿入の試行
    Set swBomTable = swView.InsertBomTable3(swBomConfigurationOptions_e.swBomConfigurationAll, _
                                            bomConfig, 0, 0, swTableAnnotation_e.swTableAnnotation_Right, False)
    
    If swBomTable Is Nothing Then
        ' 既にBOMが存在する場合の取得ロジック
        Set swBomTable = GetExistingBom(swView)
    End If

    If Not swBomTable Is Nothing Then
        Set swTable = swBomTable
        
        ' 4. 列の完全制御ロジック
        ControlBomColumns swTable
    End If

CleanUp:
    ' 5. リソースの解放と状態の復元
    swModel.LockGraphics = False
    swModel.ForceRebuild3 True
    
    ' オブジェクトの明示的解放(重要)
    Set swBomTable = Nothing
    Set swTable = Nothing
    Set swView = Nothing
    Set swSheet = Nothing
    Set swDraw = Nothing
    Set swModel = Nothing
    Set swApp = Nothing
    Exit Sub

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

''' <summary>
''' プロパティ名に基づき、列の順序・表示・幅を制御する
''' </summary>
Private Sub ControlBomColumns(swTable As SldWorks.TableAnnotation)
    Dim i As Integer
    Dim colCount As Integer
    Dim colPropName As String
    Dim targetProp As String
    Dim targetOrder As Variant
    Dim currentOrderIdx As Integer
    
    colCount = swTable.ColumnCount
    
    ' --- 設定セクション: ここをマスターデータから読み込む設計にすべき ---
    ' 表示したいプロパティの順序を定義
    targetOrder = Array("PartNo", "Description", "Quantity", "Material")
    ' ------------------------------------------------------------------

    ' A. 不要な列の非表示化と列幅の初期化
    For i = 0 To colCount - 1
        ' 列のプロパティ名を取得(ヘッダーではなく、内部的なデータソース名)
        ' 注: APIの仕様により、ヘッダー文字列で判定する必要がある場合もある
        colPropName = swTable.GetColumnName(i)
        
        ' 定義されたリストにないプロパティは非表示にする
        If Not IsInArray(colPropName, targetOrder) Then
            swTable.SetColumnVisible i, False
        Else
            swTable.SetColumnVisible i, True
            ' 列幅の最適化(実務では固定値、または文字数に基づく計算を行う)
            swTable.SetColumnWidth i, 3000 ' 0.001m単位
        End If
    Next i

    ' B. 列の並び替え(再配置)
    ' 注意: SolidWorks APIのTableAnnotationには直接的な「MoveColumn」がない場合が多い。
    ' その場合、列のデータのコピーと削除、あるいはテンプレート側での制御が推奨されるが、
    ' ここでは「目的の列を特定して制御する」という論理構造を示す。
    ' 実際の実務では、テンプレートの列順を固定し、コードからは「表示/非表示」のみを制御するのが最も安全である。
End Sub

''' <summary>
''' 配列内に値が存在するか判定するヘルパー関数
''' </summary>
Private Function IsInArray(val As String, arr As Variant) As Boolean
    Dim i As Long
    For i = LBound(arr) To UBound(arr)
        If arr(i) = val Then
            IsInArray = True
            Exit Function
        End If
    Next i
    IsInArray = False
End Function

''' <summary>
''' 既存のBOMテーブルを探索する
''' </summary>
Private Function GetExistingBom(swView As SldWorks.View) As SldWorks.BomTableAnnotation
    Dim swAnn As SldWorks.Annotation
    Dim swTableAnn As SldWorks.TableAnnotation
    
    Set swAnn = swView.GetFirstAnnotation2
    Do While Not swAnn Is Nothing
        If swAnn.GetType = swAnnotationType_e.swTableAnnotation Then
            Set swTableAnn = swAnn
            Set GetExistingBom = swTableAnn.GetBomTable
        End If
        Set swAnn = swAnn.GetNext
    Loop
End Function

4. アーキテクトの視点:保守性と拡張性

このコードを実務のシステムに組み込む際、以下の3点を考慮せよ。

4.1. テンプレート依存性の排除

コード内にプロパティ名(`”PartNo”`, `”Material”` 等)をハードコードするのは、小規模なスクリプトでは許容されるが、エンタープライズ環境では罪悪である。これらは必ず外部のCSV、Excel、あるいはシステムのデータベースから取得するように設計せよ。

4.2. エラーハンドリングの階層化

`On Error GoTo ErrorHandler` は最低限の作法だ。真のプロフェッショナルは、ネットワーク切断、ファイルロック、メモリ不足といった「予期せぬ事態」を想定し、エラーが発生した際にも `swModel.LockGraphics = False` を確実に実行して、SolidWorksのユーザーインターフェースを「使用不能状態」にさせない設計を行う。

4.3. Windows APIとの連携(極限の領域)

もし、図面生成中にファイル共有サーバーのネットワーク遅延がボトルネックになる場合は、VBAの限界を超え、Windows API (`kernel32.dll`) を用いたファイルロックの確認や、プロセス優先度の制御を検討する必要がある。しかし、まずはSolidWorks APIのライフサイクルを完璧に理解することが先決だ。

結論

BOMの自動配置は、単なる「見た目の調整」ではない。それは、設計データという抽象的な情報を、製造という物理的なプロセスへと繋ぐ「インターフェースの構築」である。

インデックスに頼らず、オブジェクトの寿命を支配し、描画コストを計算する。この規律こそが、凡庸な自動化ツールと、伝説的な業務システムを分かつ境界線である。

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