【テクニカル・上級編】【画面再描画の完全制御】SwApp.EnableUserInterfaceとVisibleStateChangeによる圧倒的なマクロ高速化手法 – SolidWorks VBA解析バイブル

スポンサーリンク

【画面再描画の完全制御】SwApp.EnableUserInterfaceとVisibleStateChangeによる圧倒的なマクロ高速化手法

SolidWorks VBAの開発現場において、数千点規模のアセンブリ構造解析や、全コンポーネントに対する一括プロパティ書き換えといったバッチ処理を行った際、画面が激しくちらつき、処理が完了するまでにコーヒーを一杯飲み干せるほどの時間がかかる……。そんな絶望的な状況に直面したことはないだろうか。

アマチュアプログラマは「VBAだから遅い」と諦める。しかし、シニアエンジニアやプラント全体のCAD自動化を統括するアーキテクトであれば知っているはずだ。遅延の元凶はVBAの実行速度ではなく、不要なグラフィック再描画(Redraw)とUIスレッドの無駄な占有にあることを。

今回は、SolidWorks APIの根幹をなす画面描画制御の極限技術を公開する。`SldWorks.EnableUserInterface` と、イベント駆動によるステート管理を組み合わせ、マクロの実行速度を限界まで引き上げるプロフェッショナル・アーキテクチャを解説する。

1. なぜSolidWorksのマクロは遅いのか?(UIオーバーヘッドの正体)

VBAから `ModelDoc2` や `Component2` のメソッドを叩くたびに、SolidWorksのコアエンジンは以下の処理を暗黙的に実行している。

1. ジオメトリ・データの更新(メモリ上の数学モデルの変更)
2. グラフィック・パイプラインの再構築(ビューポートへの描画反映)
3. UIツリー・FeatureManagerの同期(ツリービューのアイコンや名称の更新)

特にアセンブリのループ処理において、1コンポーネント処理するごとに画面が再描画される仕様のままでいると、CPU時間の9割以上が「人間には到底認識できない描画の更新」に浪費される。

これを完全にシャットダウンし、CPUのリソースを純粋な計算処理とデータ操作にのみ集中させるのが、今回のテーマである「画面描画の完全制御」である。

2. 封印された劇薬:`SldWorks.EnableUserInterface` の正しい作法

SolidWorks APIには、UIの介入を断つためのいくつかのフラグやメソッドが存在する。その中でも最も強力なのが `SldWorks.EnableUserInterface`(またはそれに類するアプリケーションレベルの制御)だ。

しかし、この手法には「諸刃の剣」としてのリスクが伴う。処理中に予期せぬエラー(ゼロ除算やオブジェクトのNull参照など)でコードがクラッシュした場合、UIがロックされたままVBAが終了し、SolidWorksが二度と操作を受け付けないゾンビ状態に陥る。

したがって、シニアエンジニアのコードには、必ず「例外安全(Exception Safety)」を担保するエラーハンドリングが実装されていなければならない。

圧倒的な高速化を実現する堅牢なテンプレートコード

以下のコードは、エラーが発生しようとも確実にUIと描画を復旧させる、実戦投入仕様のモジュール構造である。

Option Explicit

‘ メインエントリーポイント
Public Sub ExecuteHighSpeedBatchProcess()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2

‘ 1. アプリケーションインスタンスの取得
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc

If swModel Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbCritical
Exit Sub
End If

‘ — 実行前セーフティ:処理中の画面更新を完全シャットダウン —
On Error GoTo ErrorHandler

‘ 画面描画の凍結 (Graphics Redrawの停止)
swModel.LockRefresh

‘ ユーザーインターフェースの無効化(コマンド・メニュー・ツリー更新の抑止)
‘ ※環境やバージョンによるAPI仕様の変化に備え、エラータントに扱う
Dim originalUIState As Boolean
originalUIState = swApp.EnableUserInterface(False)

Dim originalEventState As Boolean
originalEventState = swApp.SetEventNotifyState(False) ‘ イベント通知も一時停止

‘ —————————————————-
‘ ここからが高速バッチ処理本体(例:全コンポーネントの抑制状態切替など)
‘ —————————————————-
Call CoreHeavyProcessing(swModel)
‘ —————————————————-

ErrorHandler:
If Err.Number <> 0 Then
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical
End If

‘ — 実行後セーフティ:必ず元の状態に復元する(ここが極めて重要) —
On Error Resume Next

‘ 描画ロックの解除
swModel.UnlockRefresh

‘ UIの復元
swApp.EnableUserInterface (originalUIState)

‘ イベント通知の復元
swApp.SetEventNotifyState (originalEventState)

‘ 強制画面リフレッシュ
swModel.GraphicsRedraw2

On Error GoTo 0

MsgBox “高速バッチ処理が完了しました。”, vbInformation
End Sub

Private Sub CoreHeavyProcessing(ByVal swModel As SldWorks.ModelDoc2)
‘ 実際の重い処理を記述するスペース
‘ 例:数千回におよぶパラメータ変更、フィーチャー走査など
Dim i As Long
For i = 1 to 1000
‘ 画面更新が一切走らないため、極限の速度でループが回転する
Next i
End Sub

3. `VisibleStateChange` との統合:システム間連携における最適解

大規模なアセンブリをバックグラウンド(非表示状態)で処理したい場合、単にUIをロックするだけでなく、ウィンドウ自体の表示状態を制御するアプローチが極めて有効だ。

特に、PDM(Product Data Management)システムや外部ERPからSolidWorksをオートメーション経由でヘッドレス起動(UIなし)させ、一括図面生成やSTEP変換を行うようなシステム間連携の現場では、「ウィンドウの可視性(Visible State)」のコントロールが安定稼働の鍵を握る。

VisibleStateChange イベントの活用アーキテクチャ

SolidWorksの `SldWorks` オブジェクトに対してイベントハンドラを実装し、ウィンドウのロード状態や可視性の変化を監視・制御することで、メモリリークを防ぎつつバックグラウンド処理の信頼性を極限まで高めることができる。

以下は、クラスモジュール(例:`CAppEventBridge`)を用いたイベントフックの概念的実装である。

‘ ==========================================
‘ クラスモジュール: CAppEventBridge
‘ ==========================================
Option Explicit

Public WithEvents SldWorksEvent As SldWorks.SldWorks

‘ ウィンドウ状態変化時のイベントハンドラ
Private Function SldWorksEvent_VisibleStateChange(ByVal Visible As Boolean) As Long
‘ ウィンドウが非表示化・表示化された瞬間のフック処理
If Not Visible then
‘ バックグラウンド処理中の最適化ロジックをここに記述
End If
SldWorksEvent_VisibleStateChange = 0
End Function

このイベントドリブンなアプローチにより、外部システムからのバッチ実行時にSolidWorksが不意に前面に飛び出してフォーカスを奪うといった、ユーザーエクスペリエンス上の致命的な欠陥を完全に排除することが可能となる。

4. チーフアーキテクトが警鐘を鳴らす「メモリ管理」のダークパターン

画面再描画を止め、処理速度を極限まで高めたエンジニアが最後に陥る罠が「メモリリークによるSolidWorksプロセスの肥大化」である。

VBAのガベージコレクションは非常に気まぐれだ。特にSolidWorks APIのCOMオブジェクトは、明示的に解放(`Set obj = Nothing`)してやらなければ、内部のC++ヒープ領域に参照が残り続け、数千回のループを回した瞬間にメモリ不足(Out of Memory)でクラッシュする。

鉄則:オブジェクト変数のスコープ最小化と即時解放

ループ内でコンポーネントやフィーチャーを走査する際は、以下のような「使い捨ての作法」を徹底しなければならない。

Dim swFeat As SldWorks.Feature
Dim swSubFeat As SldWorks.Feature

Set swFeat = swModel.FirstFeature
Do While Not swFeat Is Nothing
‘ — 処理 —

‘ 次のフィーチャーを取得
Set swSubFeat = swFeat.GetNextFeature

‘ 【重要】現在のオブジェクト参照を即座に破棄
Set swFeat = Nothing

‘ 参照の付け替え
Set swFeat = swSubFeat
Set swSubFeat = Nothing
Loop

この「変数の使い回し」と「即座の `Nothing` 代入」の積み重ねこそが、レガシーなVBA環境であっても何時間もの連続稼働に耐えうる、鉄壁の安定性を生み出す。

総括

SolidWorks VBAにおけるパフォーマンスチューニングは、小手先のテクニックの集合体ではない。それはSolidWorksという巨大なCADエンジンのライフサイクル、スレッドモデル、そしてCOMオブジェクトのメモリ構造を完全に理解した者だけが到達できる、一種のエンジニアリング芸術である。

今回解説した `swModel.LockRefresh` と `SldWorks.EnableUserInterface` による画面描画の完全制御、そして堅牢なエラーハンドリングによる例外安全の確保。これらをあなたの開発する自動化スクリプトに組み込んだ瞬間から、数分かかっていたバッチ処理は数秒で完了する「圧倒的な現実」へと生まれ変わるはずだ。

現場の限界を突破せよ。あなたのコードが、CAD自動化の新しい基準となる。

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