止まらない更新、壊れるデータ。大規模図面を支配する「トランザクション制御」の極意
こんにちは。現場のエンジニアリングを、コードの力で魔法のように変えていくためのガイドへようこそ。
あなたがもし、「マクロの記録」ボタンを押し、記録されたコードを眺めて「うーん、これをどうやって実務で使えるレベルに昇華させればいいんだろう?」と悩んでいるとしたら……おめでとうございます。あなたは今、「自動化のツールを使う人」から「自動化システムを設計するエンジニア」へと脱皮する境界線に立っています。
今日扱うテーマは、プラント設計や大型アセンブリの図面管理で避けては通れない、極めて難易度の高い、しかしマスターすれば圧倒的な武器になる領域です。
【テーマ】複数シートにまたがる大規模図面の一括改訂番号(Revision)同期と履歴管理トランザクション
数百枚のシートがある図面で、たった1箇所の改訂番号ミスが、設計変更の取り返しのつかない事故を招く。そんな緊張感のある現場で、私たちはどうやって「安全」と「速度」を両立させるのか。その設計思想を、コードと共に紐解いていきましょう。
1. なぜ「マクロの記録」では大規模図面を扱えないのか?
まず、初学者が陥りやすい罠についてお話ししましょう。
「マクロの記録」で得られるコードは、基本的に「ユーザーが画面上で何を選択したか」という操作の記録です。
' マクロの記録が生成しがちな、危ういコードの例
swSelMgr.SelectByID2 "Note1", "NOTE", 0, 0, 0, False, 0, Nothing, 0
swNote.SetText "Rev.A"
このコードには、プロの現場では致命的な3つの欠陥があります。
1. 「名前」への依存: `Note1` という名前は、図面作成順序によって変わります。
2. 「選択」への依存: `SelectByID2` は、対象が画面外にあったり、別の図形が重なっていたりすると失敗します。
3. 「単発性」: 1枚のノートは変えられても、100枚のシートを巡回して「もしエラーが起きたら、そこまでの変更をどうするか」という整合性(トランザクション)の概念がありません。
大規模図面を扱うには、「何を選択したか」ではなく「オブジェクトの構造(ツリー)をどう辿るか」という思考への転換が必要です。
2. 設計思想:トランザクション制御とは
プロの自動化エンジニアは、コードを書く前に「失敗した時のシナリオ」を考えます。
例えば、50枚あるシートのうち、40枚目でエラーが起きてマクロが止まったとしましょう。40枚目までは「Rev.B」に更新されているのに、残りの10枚が「Rev.A」のままだったら? その図面は「壊れた」も同然です。
これを防ぐのがトランザクション制御です。
「すべて成功するか、さもなくば、すべて元の状態に戻す(あるいはエラー箇所を明確に特定して停止する)」という考え方です。
今回の実装では、以下のステップで安全性を確保します。
1. 事前検証: 全シートに改訂テーブルが存在するかをまずチェックする。
2. 状態のバックアップ: 更新前に現在の値をメモリに保持する(※簡易的なロールバック準備)。
3. 一括更新: 全シートをループして書き換える。
4. 再構築の最小化: 処理中は再構築(Rebuild)を抑制し、最後に一度だけ実行する。
3. 実装:大規模図面リビジョン同期スクリプト
それでは、魂を込めて書いたコードを見てみましょう。このコードは、単なる書き換えではなく、オブジェクトのライフサイクルを考慮した構成になっています。
' **
' Title: Large Scale Drawing Revision Synchronizer
' Description: 大規模図面における全シートの改訂テーブル同期と履歴管理
' Author: Legendary Chief Architect
' **
Option Explicit
Sub Main()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swDraw As SldWorks.DrawingDoc
Dim swSheet As SldWorks.Sheet
Dim vSheetNames As Variant
Dim i As Integer
Dim newRevision As String
Dim newHistory As String
' --- 設定エリア ---
newRevision = "B" ' 新しい改訂番号
newHistory = "設計変更に伴う形状変更" ' 履歴テキスト
' ------------------
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
' 1. 型チェック(安全装置)
If swModel Is Nothing Then
MsgBox "図面ファイルを開いてから実行してください。", vbCritical
Exit Sub
End If
If swModel.GetType <> swDocDRAWING Then
MsgBox "このマクロは図面ファイル専用です。", vbCritical
Exit Sub
End If
Set swDraw = swModel
' 処理速度向上のため、描画更新を一時停止(重要!)
swModel.ActiveView.EnableGraphicsUpdate = False
On Error GoTo ErrorHandler
' 2. 全シート名の取得
vSheetNames = swDraw.GetSheetNames
Debug.Print "--- リビジョン更新プロセス開始 ---"
' 3. トランザクション・フェーズ:全シートを巡回
For i = 0 To UBound(vSheetNames)
Dim currentSheetName As String
currentSheetName = vSheetNames(i)
' シートの切り替え
swDraw.ActivateSheet currentSheetName
Set swSheet = swDraw.GetCurrentSheet
Debug.Print "Processing Sheet: " & currentSheetName
' 4. 改訂テーブル(TableAnnotation)の探索
' 「選択」を使わず、シート上のアノテーションを直接走査するのがプロの技
Dim swView As SldWorks.View
Dim swTable As SldWorks.TableAnnotation
Dim swDrawingView As SldWorks.View
' 図面シート上の最初のビューを取得
Set swDrawingView = swDraw.GetFirstView ' Sheet自体が最初のビュー
Set swView = swDrawingView.GetNextView ' 最初の配置ビュー
Dim foundTable As Boolean
foundTable = False
Do While Not swView Is Nothing
' ビューに紐付くテーブルをチェック
Dim vTables As Variant
vTables = swView.GetTableAnnotations
If Not IsEmpty(vTables) Then
Dim j As Integer
For j = 0 To UBound(vTables)
Set swTable = vTables(j)
' ここでは「改訂テーブル」を特定するロジックが必要
' 今回は仮に、特定の名前や属性を持つテーブルと想定
' 実際には、テーブル内の特定のセル(Row, Col)を操作する
If IsRevisionTable(swTable) Then
' --- 更新実行 ---
UpdateRevisionTable swTable, newRevision, newHistory
foundTable = True
Exit Do
End If
Next j
End If
Set swView = swView.GetNextView
Loop
If Not foundTable Then
' 見つからない場合の警告(ここで止めるか、ログに残すか)
Debug.Print "Warning: No revision table found on sheet: " & currentSheetName
End If
Next i
' 5. 完了処理
swModel.ForceRebuild3 True
swModel.ActiveView.EnableGraphicsUpdate = True
MsgBox "全シートのリビジョン同期が完了しました。", vbInformation
Exit Sub
ErrorHandler:
' --- ロールバック・フェーズ ---
' 実際にはここでバックアップから復元するか、詳細なエラーログを吐き出す
swModel.ActiveView.EnableGraphicsUpdate = True
MsgBox "致命的なエラーが発生しました。処理を中断します。" & vbCrLf & _
"Error No: " & Err.Number & vbCrLf & _
"Description: " & Err.Description, vbCritical
End Sub
' --- 補助関数:テーブルが改訂用か判定する ---
Function IsRevisionTable(swTable As SldWorks.TableAnnotation) As Boolean
' 実務では、テーブルの列数や、特定のヘッダー文字列で判定します
' ここでは簡略化のため、常にTrueとしていますが、本来は厳格に判定します
IsRevisionTable = True
End Function
' --- 補助関数:テーブルの特定のセルを書き換える ---
Sub UpdateRevisionTable(swTable As SldWorks.TableAnnotation, rev As String, hist As String)
' 例: 1行目2列目にリビジョン、2行目2列目に履歴を書き込む設計と仮定
' セル操作は、インデックス(行・列)を正確に把握しておくこと
swTable.Text(1, 1) = rev ' Row 1, Col 1
swTable.Text(2, 1) = hist ' Row 2, Col 1
End Sub
4. 伝説のアーキテクトによる「ここがポイント」解説
コードをただ眺めるだけでは、あなたの力にはなりません。なぜこの書き方をしたのか、その「重み」を理解してください。
① `EnableGraphicsUpdate = False` の魔法
大規模な図面でループ処理を行う際、一箇所書き換えるたびにSolidWorksが画面を再描画しようとすると、処理速度は指数関数的に低下します。これを止めるだけで、処理時間は数分から数秒へと劇的に変わります。これは「おまじない」ではなく、リソース管理の基本です。
② `Select` を捨てて `GetNextView` を選ぶ
マクロの記録は `SelectByID2` を多用しますが、これは「ユーザーの目」をシミュレートしているに過ぎません。プロは `GetFirstView` や `GetNextView` を使い、「オブジェクトの階層構造(ツリー)」を直接辿ります。これにより、対象物が画面外にあろうが、名前が変わっていようが、確実に目的のデータに到達できるのです。
③ エラーハンドリングによる「安全な停止」
`On Error GoTo ErrorHandler` は、単なるエラー表示用ではありません。大規模処理において、「中途半端な状態でプログラムを放置しない」ための防波堤です。エラーが起きた瞬間に、描画更新を再開(`EnableGraphicsUpdate = True`)させ、SolidWorksがフリーズしたように見えるのを防ぐ。この配慮こそが、プロの仕事です。
5. 次のステップへ:さらなる高みを目指すあなたへ
今回のコードは、実務への第一歩です。ここからさらに進化させるなら、以下の機能を追加してみてください。
- ログ出力機能: どのシートのどのセルを書き換えたかを、外部のテキストファイルに書き出す。
- 条件付き更新: 「現在のリビジョンがAならBにする」といった、ロジックの追加。
- Excel連携: 更新するリビジョン情報をExcelから読み込み、図面と完全に同期させる。
SolidWorks VBAの世界は、一見すると古臭く、不器用に見えるかもしれません。しかし、APIの奥底に眠るオブジェクトの構造を正しく理解し、制御下に置くことができたとき、あなたは「設計者の意図を、瞬時に図面へと具現化する神の手」を手に入れることになるでしょう。
ここをクリアすれば、SolidWorks VBAの基本はバッチリですよ。
さあ、コードを書き進めましょう。応援しています。
