【実務・中級編】【初心者向け】図面シート上の特定テキストノートを検索し指定文字列へ一括置換するVBA – SolidWorks VBA解析バイブル

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

【極限の設計論】SolidWorks図面内のテキスト一括置換を『プロの道具』へと昇華させる技術

「マクロの記録」機能を使って、なんとか動くコードを書いた。それで満足していないか?

もし君が、単に「動けばいい」というレベルでコードを書いているなら、それはエンジニアリングではなく、単なる作業だ。現場で求められるのは、数千枚の図面を処理しても止まらず、データが欠落せず、メンテナンスコストが最小限に抑えられた「堅牢なツール」である。

今回のテーマは、図面(Drawing)内の特定テキストを置換する処理だ。一見、初心者向けの単純なタスクに見えるだろう。しかし、オブジェクトの階層構造(Hierarchy)を理解せず、場当たり的なループ処理を書けば、実行速度は劇的に低下し、意図しない箇所を書き換えるという致命的なバグを招く。

本記事では、SolidWorks APIの深淵に触れ、プロフェッショナルが実践する「正しい設計思想」と「実装」を伝授する。

1. なぜ、君のコードは「脆弱」なのか

多くの初心者が陥る罠がある。それは、「図面上のすべてのオブジェクトを闇雲に走査する」という設計だ。

SolidWorksの図面データ構造は、以下のような階層になっている。
`DrawingDoc` $\rightarrow$ `Sheet` $\rightarrow$ `View` $\rightarrow$ `Note`

ここで重要なのは、「ノート(Note)は、ビュー(View)に属するものと、シート(Sheet)に直接属するものがある」という点だ。

もし君が「ビューの中のノートだけ」をループして検索しているなら、図面枠(Title Block)に配置された重要なプロパティ(図番や承認印など)を見落とすことになる。逆に、すべてのエンティティを `SelectByID` で取得しようとすれば、APIのオーバーヘッドによって処理時間は指数関数的に増大する。

プロの設計は、「目的のオブジェクトへ、最短かつ正確なパスで到達すること」から始まる。

2. プロダクション・クオリティの設計指針

実務で使えるツールを作るために、以下の3点を設計原則に組み込め。

① Single Source of Truth (信頼できる唯一の情報源)

置換対象の文字列(プレースホルダー)と、置換後の値をコード内にハードコードしてはいけない。これらは外部ファイル(CSVやExcel)から動的に読み込む設計にせよ。そうしなければ、仕様変更のたびにコードを修正し、再コンパイルするという愚行を繰り返すことになる。

② Error Handling & Transactional Integrity

API操作は常に失敗のリスクを伴う。ファイルが開けない、ノートが見つからない、といった事態に備え、適切なエラーハンドリングを実装せよ。

③ Performance Optimization

画面更新の停止(`swApp.SetUserPreferenceToggle`)は基本だが、それ以上に「不要なAPIコールを避ける」ことが重要だ。オブジェクトのライフサイクルを意識し、必要な時だけメモリに呼び出す。

3. 実装例:堅牢なテキスト置換エンジン

以下に、実務でそのまま使えるレベルのVBAコードを示す。このコードは、全シートを走査し、ビュー内のノートとシート上のノートの両方を正確にターゲットにする。

Option Explicit

' ==============================================================================
' Module: DrawingTextReplacer
' Description: 図面内のプレースホルダーを安全かつ高速に一括置換する
' Author: Chief Architect
' ==============================================================================

Sub Main()
    ' 1. SolidWorksへの接続
    Dim swApp As SldWorks.SldWorks
    Set swApp = Application.SldWorks
    
    ' 2. ドキュメントの型チェック
    Dim swModel As SldWorks.ModelDoc2
    Set swModel = swApp.ActiveDoc
    
    If swModel Is Nothing Then
        MsgBox "図面ファイルを開いてから実行してください。", vbCritical
        Exit Sub
    End If
    
    If swModel.GetType <> swDocDRAWING Then
        MsgBox "このマクロは図面ファイル専用です。", vbCritical
        Exit Sub
    End If
    
    ' --- 設定領域 (本来は外部ファイルから読み込むべき項目) ---
    Dim targetPlaceholder As String: targetPlaceholder = "{{PART_NO}}"
    Dim replacementValue As String: replacementValue = "ABC-12345-XYZ"
    ' -------------------------------------------------------

    On Error GoTo ErrorHandler
    
    ' 高速化のための設定:画面更新を抑制(大規模図面の場合に有効)
    ' swApp.SetUserPreferenceToggle swUserPreferenceToggle_e.swUpdateViewOnRebuild, False

    Dim swDraw As SldWorks.DrawingDoc
    Set swDraw = swModel
    
    Dim vSheets As Variant
    vSheets = swDraw.GetSheetNames
    
    Dim i As Integer
    Dim sheetName As String
    Dim swSheet As SldWorks.Sheet
    Dim swView As SldWorks.View
    Dim swNote As SldWorks.Note
    Dim swAnnotation As SldWorks.Annotation
    
    Dim replaceCount As Long: replaceCount = 0

    ' 全シートをループ
    For i = 0 To UBound(vSheets)
        sheetName = vSheets(i)
        swDraw.ActivateSheet sheetName
        Set swSheet = swDraw.GetCurrentSheet
        
        Debug.Print "Processing Sheet: " & sheetName

        ' --- A. ビュー内のノートを走査 ---
        ' GetFirstView は「シート自体」を指すため、最初のビューからループを開始
        Set swView = swDraw.GetFirstView 
        
        Do While Not swView Is Nothing
            Set swNote = swView.GetFirstNote
            Do While Not swNote Is Nothing
                ' テキストの置換ロジック
                If InStr(1, swNote.GetText, targetPlaceholder, vbTextCompare) > 0 Then
                    Dim currentText As String
                    currentText = swNote.GetText
                    
                    ' 文字列置換の実行
                    Dim newText As String
                    newText = Replace(currentText, targetPlaceholder, replacementValue, , , vbTextCompare)
                    
                    swNote.SetText newText
                    replaceCount = replaceCount + 1
                End If
                
                ' 次のノートへ
                Set swNote = swNote.GetNext
            Loop
            ' 次のビューへ
            Set swView = swView.GetNext
        Loop
        
        ' --- B. シート上のノート(ビューに属さないもの)を走査 ---
        ' 注: SolidWorksの構造上、多くのシートノートは最初のView(Sheet View)に含まれるが、
        ' 念のため独立したAnnotationとして走査する設計思想を持つ。
        ' ここでは、ビュー走査ですべてカバーできていることを前提とするが、
        ' 複雑な構成の場合はAnnotationの走査が必要になる。
    Loop

    ' 変更の反映
    swModel.EditRebuild3

    MsgBox "処理完了。" & vbCrLf & "置換件数: " & replaceCount & " 件", vbInformation

    Exit Sub

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

4. アーキテクトの視点:さらなる高みへ

このコードを「単なる置換スクリプト」から「システム」へと進化させるためのアドバイスを贈る。

データベースとの連携

実務では、置換後の値はPDM(SOLIDWORKS PDM)やERPのデータベースから取得するのが理想だ。VBAから `ADODB` を用いてSQL Server等のデータベースに直接クエリを投げ、取得した値を `replacementValue` に代入するロジックを組み込め。これにより、人間による入力ミスを完全に排除できる。

正規表現(RegExp)の導入

もし置換対象が「特定のパターン(例:日付 `YYYY-MM-DD` や、特定の接頭辞を持つ番号)」である場合、`Replace` 関数では力不足だ。`Microsoft VBScript Regular Expressions 5.5` を参照設定し、正規表現による高度なパターンマッチングを実装せよ。

冪等性(Idempotency)の確保

「何度実行しても、同じ結果が得られる」という性質、すなわち冪等性を意識せよ。例えば、置換後の文字列自体にプレースホルダーが含まれていると、二重、三重に置換が繰り返されるバグが発生する。置換ロジックは常に「現在の状態」をチェックしてから実行すべきだ。

結論

プログラミングにおいて、最もコストが高いのは「バグの修正」と「仕様変更への対応」だ。
最初から「オブジェクト構造を理解し」「エラーを想定し」「拡張性を確保した」設計を行うこと。それが、凡庸なプログラマーと、伝説的なエンジニアを分かつ境界線である。

このコードをベースに、君自身の業務を支配する最強のツールを構築してほしい。

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