【極限の知見】SolidWorks VBA:図面承認フローを動的に制御する「データ駆動型」設計思想
設計現場において、「図面作成の自動化」は単なる作業時間の短縮ではない。それは、「人為的ミスの排除」と「情報の整合性確保」という、品質保証(QA)への挑戦である。
多くの開発者が陥る罠がある。それは、図面の表題欄(タイトルブロック)の書き換えを、`If…Then` や `Select Case` による条件分岐の羅列で実装してしまうことだ。
「部品図ならAさんの名前、アセンブリ図ならBさんとCさんの名前を……」
このようなハードコーディングは、組織変更や承認フローの変更が生じた瞬間に、技術負債へと変貌する。本稿では、中級者への階段を駆け上がるために必要な、「データとロジックの分離」に基づいた、堅牢な図面制御アーキテクチャを伝授する。
1. 凡庸なコードと、プロフェッショナルの設計の違い
まず、君たちが書こうとしているコードを客観的に見つめ直してほしい。
❌ アンチパターン:条件分岐の迷宮
' これが典型的な「壊れやすい」コードだ
If docType = swDocPART Then
SetProperty "DESIGNER", "田中"
SetProperty "CHECKER", "佐藤"
ElseIf docType = swDocASSEMBLY Then
SetProperty "DESIGNER", "田中"
SetProperty "CHECKER", "鈴木"
SetProperty "APPROVER", "高橋"
End If
このコードの何が問題か? 答えは単純だ。「仕様(誰が承認するか)」と「実行(書き換える処理)」が密結合している点にある。承認者が変わるたびに、VBAのソースコードを書き換え、再コンパイルし、配布し直すのか? そんなことはプロの仕事ではない。
✅ プロフェッショナルの方針:データ駆動型(Data-Driven)
我々が目指すべきは、「図面の種類」と「適用すべき承認データ」を外部(CSV、Excel、あるいはデータベース)から取得し、ロジックはそれを流し込むだけの「器」に徹する設計である。
2. 技術的要諦:シートフォーマットとブロックの制御
SolidWorks APIにおいて、表題欄の操作は一筋縄ではいかない。表題欄は通常、「Sheet Format(シートフォーマット)」として定義されたビュー内に存在する「Block(ブロック)」である。
ここでの核心は、以下のオブジェクト階層を正確に掌握することだ。
1. `DrawingDoc` (図面ドキュメント)
2. `DrawingSheet` (図面シート)
3. `View` (シートフォーマット自体も一つのViewとして扱われる)
4. `BlockInstance` (ブロックのインスタンス)
5. `Annotation` / `Custom Property` (テキスト情報の書き換え)
特に、「シートフォーマットのビュー」を特定するプロセスが、バグを防ぐ鍵となる。
3. 実装:プロダクション・グレードの制御ロジック
以下に、実務でそのまま使えるレベルの堅牢なコード構造を示す。ここでは、承認フローの定義を「Dictionaryオブジェクト(または外部データ)」から取得する想定で記述する。
Option Explicit
' ==============================================================================
' 承認フロー制御モジュール
' 設計思想: ロジックとデータを分離し、エラーハンドリングを徹底する
' ==============================================================================
Sub Main()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
' 1. ドキュメント型のバリデーション
If swModel Is Nothing Then Exit Sub
If swModel.GetType <> swDocDRAWING Then
MsgBox "図面ファイルを開いた状態で実行してください。", vbCritical
Exit Sub
End If
On Error GoTo ErrorHandler
' 2. 実行コンテキストの解析
Dim docType As Long
docType = swModel.GetType ' 本来は参照しているモデルの型を確認すべき
' ※図面ファイルの場合、参照しているモデルの型を取得するロジックが必要
Dim refModel As SldWorks.ModelDoc2
Set refModel = GetReferencedModel(swModel)
If refModel Is Nothing Then
MsgBox "参照モデルが見つかりません。", vbExclamation
Exit Sub
End If
' 3. 承認データの取得 (本来はCSVやDBから取得する)
' ここではシミュレーションとして、Dictionary的な構造を想定
Dim approvalData As Object
Set approvalData = GetApprovalFlowMapping(refModel.GetType)
' 4. 図面への書き込み実行
UpdateTitleBlock swModel, approvalData
' 5. 画面更新と再構築
swModel.ForceRebuild3 True
MsgBox "承認スタンプの更新が完了しました。", vbInformation
Exit Sub
ErrorHandler:
MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical
End Sub
' ------------------------------------------------------------------------------
' 関数: 参照モデルの型に基づき、適用すべき承認者セットを返す
' ------------------------------------------------------------------------------
Private Function GetApprovalFlowMapping(modelType As Long) As Object
' 本来はここで外部ファイル(CSV/Excel)を読み込む
' ここでは、プロダクションコードの構造を示すためにDictionaryを使用
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
If modelType = swDocPART Then
' 部品図用のフロー
dict.Add "DESIGNER", "田中 太郎"
dict.Add "CHECKER", "佐藤 次郎"
ElseIf modelType = swDocASSEMBLY Then
' アセンブリ図用のフロー
dict.Add "DESIGNER", "田中 太郎"
dict.Add "CHECKER", "鈴木 一郎"
dict.Add "APPROVER", "高橋 三郎"
End If
Set GetApprovalFlowMapping = dict
End Function
' ------------------------------------------------------------------------------
' 関数: 図面シートのブロック内プロパティを更新する
' ------------------------------------------------------------------------------
Private Sub UpdateTitleBlock(swDrawing As SldWorks.DrawingDoc, data As Object)
Dim swSheet As SldWorks.DrawingSheet
Dim swView As SldWorks.View
Dim swBlockInst As SldWorks.BlockInstance
Dim vKeys As Variant
Dim key As Variant
Set swSheet = swDrawing.GetCurrentSheet
' シートフォーマット(一番最初のView)を取得
Set swView = swSheet.GetFirstView
' シートフォーマットの中にブロックが存在するか確認
' ※BlockInstanceを取得するために、Viewのプロパティを走査
If Not swView Is Nothing Then
' ブロックインスタンスを取得(シートフォーマットは通常、最初のViewに紐付く)
' ここでは、汎用性を高めるため、すべてのViewからブロックを探す設計にする
Do While Not swView Is Nothing
If swView.IsBlock Then
Set swBlockInst = swView.GetBlockInstance
' データの流し込み
vKeys = data.Keys
For Each key In vKeys
' カスタムプロパティ(またはブロック内の特定のテキスト属性)を更新
' ここでは最も堅牢な「カスタムプロパティ経由の連動」を想定
' ブロック内のテキストがカスタムプロパティにリンクされている設計がベスト
swDrawing.CustomPropertyManager("").Set2 CStr(key), swCustomInfoText, CStr(data(key))
Next key
End If
Set swView = swView.GetNextView
Loop
End If
End Sub
' ------------------------------------------------------------------------------
' 関数: 図面から参照されているモデルを取得する(堅牢性のための補助関数)
' ------------------------------------------------------------------------------
Private Function GetReferencedModel(swDrawing As SldWorks.DrawingDoc) As SldWorks.ModelDoc2
Dim swView As SldWorks.View
Set swView = swDrawing.GetFirstView ' FirstViewはSheet自体なので、Nextから開始
Set swView = swView.GetNextView ' これが最初の配置ビュー
If Not swView Is Nothing Then
Set GetReferencedModel = swView.ReferencedDocument
Else
Set GetReferencedModel = Nothing
End If
End Function
4. 伝説のアーキテクトによる「極限の知見」:運用を支える3つの鉄則
コードが書けた。しかし、それで満足してはいけない。実務でこのツールを「プロダクション・レベル」に引き上げるには、以下の3点を設計に組み込む必要がある。
① カスタムプロパティとブロックの「リンク」を利用せよ
ブロック内のテキストを直接 `TextEdit` で書き換える手法は、座標計算やフォント制御の面で極めて脆弱だ。
「ブロック内のテキストを、図面ドキュメントのカスタムプロパティにリンクさせておく」。これがSolidWorksにおける正攻法である。そうすれば、VBA側は `CustomPropertyManager` を叩くだけで、ブロック内の見た目が自動的に更新される。オブジェクトのライフサイクルを追う必要すらなくなるのだ。
② 参照モデルの「存在確認」を怠るな
図面には、参照モデルが壊れている(SuppressedやMissing)場合がある。`swView.ReferencedDocument` が `Nothing` を返した際のハンドリングを怠ると、ツールは即座にクラッシュする。例外処理(`On Error`)は、単なる飾りではない。エンジニアの責任感の現れだ。
③ パフォーマンスの重み:Rebuildの制御
ループの中で `ForceRebuild` を呼び出す愚か者がいる。これは致命的なパフォーマンス低下を招く。
「全てのデータ変更を終えてから、最後に一度だけ再構築する」。この原則を守るだけで、大規模アセンブリ図面における処理速度は劇的に向上する。
結論
自動化エンジニアの価値は、単に「動くコード」を書くことではない。「変化に強く、メンテナンスコストが極めて低いシステム」を構築することにある。
今回提示した「データ駆動型」の設計思想を、君の次のプロジェクトに持ち込んでほしい。コードの向こう側にある「運用」を見据えた時、君のツールは真に価値ある資産へと昇華するはずだ。
