【入門編】【上級プロ】マルチプロセッサ環境を模倣したバックグラウンド処理:大規模アセンブリのエクスポート中にUIのフリーズを防ぐ進捗管理 – SolidWorks VBA解析バイブル

スポンサーリンク

こんにちは!SolidWorks VBAの世界へようこそ。
日々、何百もの部品が組み合わさった巨大なアセンブリを扱っていて、「あー、STEPやIGESへのエクスポート中にSolidWorksがフリーズした……。生きてるのかこれ?」とコーヒー片手に画面を見つめた経験はありませんか?

マクロの記録から一歩抜け出し、現場で戦うエンジニアになったあなたなら、一度はぶ壁る悩みですよね。
今回は、大規模アセンブリを処理する際の「UIのフリーズ問題」を鮮やかに解決し、まるでマルチプロセッサで動いているかのような滑らかなプログレスバー付きUIを実装する、上級プロの知見を授けましょう。

ここをクリアすれば、あなたの作るマクロは単なる「お助けツール」から、現場で絶賛される「プロ仕様のシステム」へと生まれ変わります。一緒に本質を学んでいきましょう!

—

なぜ大規模アセンブリのエクスポートでSolidWorksはフリーズするのか?

SolidWorks VBA(COMオートメーション)は、基本的にシングルスレッドで動作します。
つまり、VBAから「エクスポートしろ!」と命令を投げると、SolidWorksのメインスレッド(画面を描画したり、マウスの入力を受け付けたりする頭脳)がその重たい計算処理に完全占有されてしまいます。

結果として、Windowsは「このアプリ、応答なしだな」と判断し、画面が真っ白に固まる――これがフリーズの正体です。

解決の鍵:`DoEvents` と非同期的な思考

ここで登場するのが、Windows APIの息吹を感じさせる `DoEvents` 関数です。
`DoEvents` は、VBAに一時停止を命じ、その間に溜まっているWindowsのメッセージ(「ボタンが押されたよ」「画面を再描画してね」といったイベント)を処理させる魔法の呪文です。

これを使うことで、重たいループ処理の合間にWindowsへ「ちょっと息継ぎタイム!」を与え、UI(ユーザーインターフェース)のフリーズを防ぎながら、滑らかなプログレスバーを動かすことが可能になります。

—

実装:プログレスバー付き・非同期風エクスポートマクロ

百聞は一見にしかず。まずは、実際の現場でそのまま使える洗練されたコードを見てみましょう。
今回は、アセンブリ内のコンポーネントを巡回し、一つずつ何らかの重たい処理(ここではエクスポートを想定したダミー含む)を行いつつ、進捗状況をユーザーフォームに美しく表示するコードです。

1. ユーザーフォームの準備(概念)

画面上に `UserForm1` を作成し、以下のコントロールを配置してください。

  • Label1 (進捗メッセージ表示用:「部品 A を処理中…」など)
  • ProgressBar1 (Microsoft ProgressBar Control、または枠線を変形させたシンプルなLabelでも代用可)

2. 標準モジュールに記述するメインコード

Option Explicit

‘ 処理のキャンセルやWindowsへの制御権委譲を行うためのAPI宣言(必要に応じて)
Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)

Sub ExportLargeAssemblyWithProgress()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssoc As SldWorks.AssemblyDoc
Dim vComps As Variant
Dim i As Long
Dim totalComps As Long
Dim progressVal As Double

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

‘ ドキュメントが開かれているか、かつアセンブリかチェック
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントがありません。”, vbCritical, “エラー”
Exit Sub
End If

If swModel.GetType <> swDocASSEMBLY Then
MsgBox “対象はアセンブリである必要があります。”, vbCritical, “エラー”
Exit Sub
End If

Set swAssoc = swModel

‘ アセンブリ内の全コンポーネントを取得(トップレベル)
vComps = swAssoc.GetComponents(True)
If IsEmpty(vComps) Then
MsgBox “コンポーネントが見つかりません。”, vbExclamation, “警告”
Exit Sub
End If

totalComps = UBound(vComps) – LBound(vComps) + 1

‘ 進捗表示用のユーザーフォームをモードレス(操作可能)で表示
Load UserForm1
UserForm1.Show vbModeless
UserForm1.LabelTitle.Caption = “大規模アセンブリ エクスポート実行中…”

‘ — メインの爆速・快適ループ —
For i = LBound(vComps) To UBound(vComps)
Dim swComp As SldWorks.Component2
Set swComp = vComps(i)

‘ フォームの表示を更新
progressVal = (CSng(i + 1) / totalComps) 100
UserForm1.UpdateProgress progressVal, “処理中: ” & swComp.Name2

‘ ==========================================
‘ ここに本来の重たい処理(STEP変換やパラメータ変更など)を記述
‘ プレビューとして一時停止(Sleep)を挟んでいます
Call HeavyTaskSimulation
‘ ==========================================

‘ 【最重要】Windowsに制御を戻し、UIのフリーズを完全に防ぐ
DoEvents

‘ ユーザーが「キャンセル」ボタンを押した場合の脱出ロジック
If UserForm1.IsCancelled = True Then
If MsgBox(“処理を中断しますか?”, vbYesNo + vbQuestion, “確認”) = vbYes Then
Unload UserForm1
MsgBox “ユーザーによって処理が中断されました。”, vbInformation, “中断”
Exit Sub
Else
UserForm1.IsCancelled = False ‘ キャンセル解除して続行
End If
End If
Next i

‘ 後片付け
Unload UserForm1
MsgBox “すべてのエクスポート処理が正常に完了しました!”, vbInformation, “完了”

End Sub

‘ 重たい処理のシミュレーション(実務ではここにAPIのエクスポート処理が入る)
Private Sub HeavyTaskSimulation()
‘ 0.05秒の負荷を模倣
Sleep 50
End Sub

3. ユーザーフォーム(`UserForm1`)側のコード

フォームに配置したプログレスバーやラベルを安全に更新するためのメソッドを用意します。

Option Explicit

‘ キャンセルフラグ
Public IsCancelled As Boolean

‘ 初期化時
Private Sub UserForm_Initialize()
IsCancelled = False
ProgressBar1.Value = 0
End Sub

‘ 「キャンセル」ボタンが押されたとき
Private Sub btnCancel_Click()
IsCancelled = True
End Sub

‘ 外部から呼び出される進捗更新メソッド
Public Sub UpdateProgress(ByVal percent As Double, ByVal statusText As String)
‘ パーセンテージの丸め処理(0〜100の範囲に収める)
If percent < 0 Then percent = 0 If percent > 100 Then percent = 100

‘ プログレスバーとラベルの更新
Me.ProgressBar1.Value = percent
Me.LabelStatus.Caption = statusText

‘ フォーム自体のタイトルにも進捗率を表示して親切に
Me.Caption = “処理中… (” & Format(percent, “0.0”) & “%)”
End Sub

—

D何故このコードが「上級プロ仕様」なのか、その設計思想を少し深掘りしましょう。

1. `vbModeless` によるユーザーインターフェースの開放
`UserForm1.Show vbModeless` を使っている点がポイントです。通常のマクロで使われる `vbModal` だと、フォームが開いている間は背面のSolidWorksはもちろん、フォーム以外の操作が完全にロックされます。モデルレスにすることで、ユーザーが「キャンセル」ボタンを押す権利を常に担保できます。
2. `DoEvents` の適切な頻度
ループの1回ごとに `DoEvents` を挟んでいます。これによって、Windowsのメッセージキューが綺麗に掃き出され、プログレスバーが滑らかにアニメーションします(あまりに処理が軽すぎるループで毎回 `DoEvents` を呼ぶと逆にオーバーヘッドになるため、数コンポーネントに1回に間引くテクニックも実務では有効です)。
3. キャンセルフラグの非同期キャッチ
巨大なアセンブリを処理している最中に「あ、間違えた!」と気づいたとき、キャンセルできないマクロは地獄です。このコードでは、ユーザーがキャンセルボタンを押した瞬間にフラグを立て、次のループのタイミングで優雅に処理を中断できるように設計しています。

—

陥りやすい罠:気をつけておきたいエラーと対策

  • 罠1: 「オブジェクト変数または With ブロック変数が見つかりません」
  • 原因: ループ内で取得した `swComp` が非表示(Suppress)状態だったり、コンテキストエラーを起こして `Nothing` になっている場合に、そのままプロパティを叩こうとすると発生します。
  • 対策: 大規模アセンブリでは、`If swComp Is Nothing Then GoTo ContinueLoop` のようなヌルチェックを必ず挟みましょう。
  • 罠2: `DoEvents` を過信しすぎて処理が遅くなる
  • 原因: 1つの部品の処理がコンマ数ミリ秒で終わるような軽量なループで毎回 `DoEvents` を呼ぶと、Windowsとのコンテキストスイッチが頻発し、逆に処理時間が何倍にも膨れ上がります。
  • 対策: 「10回に1回だけ `DoEvents` を呼ぶ(カウンター変数を使う)」などのチューニングを行いましょう。

—

まとめ:あなたのマクロを「プロダクト」へ昇華させよう

今回は、SolidWorks VBAにおけるマルチプロセッサ風バックグラウンド処理の模倣と、快適な進捗管理の実装方法を解説しました。

  • 重たい処理の合間に `DoEvents` を挟んでUIを生かす。
  • ユーザーフォームは `vbModeless` で表示し、いつでもキャンセルできるようにする。
  • 進捗を可視化することで、ユーザーに「止まっていない安心感」を与える。

ここをクリアできれば、あなたの書くVBAコードは、単なる「個人用の便利スクリプト」から、チーム全員が安心して使える「信頼の業務システム」へと劇的に進化します。

ぜひ明日の業務から、このテクニックをあなたのマクロに組み込んでみてください。
それでは、また次回の極限の知見でお会いしましょう。エンジニアライフを快適に!

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