【入門編】【上級者向け】Project VBAにおける非同期処理のシミュレーションとUIフリーズの回避 – Project VBA解析バイブル

スポンサーリンク

こんにちは!プロジェクト管理の現場で、日々大量のスケジュールと格闘していませんか?

「マクロを実行した途端、画面が真っ白になって固まる…」
「『応答なし』になって強制終了する恐怖に怯えながら祈っている…」

そんな経験、MS ProjectのVBAを触っているあなたなら一度はあるはずです。実はこれ、Project VBAがシングルスレッドで動作し、裏で重い処理をしている間は画面の描画(UI)に割くリソースがなくなることが原因なんです。

今回は、マクロの記録レベルを卒業し、数千行のタスクを一括処理しても「サクサク動く&今の進捗がひと目でわかる」洗練されたVBAコードを書くための極意を伝授します。
ここをクリアすれば、あなたのProject VBAのスキルは間違いなくプロの領域に到達しますよ。それでは、エンジニアの扉を開いていきましょう!

なぜProject VBAはフリーズするのか?

MS Projectで数千件のタスク構造を一斉に変更したり、リソースの割り当てを自動化したりするループ処理を回すと、Windowsはこう判断します。

> 「いまこのアプリケーションは計算で手いっぱいのようだ。ユーザーがマウスをクリックしても、画面を再描画しろと言われても、すべて後回しにしよう!」

これが「UIフリーズ(応答なし)」の正体です。
これを回避するためのアプローチが、今回解説する「非同期処理のシミュレーション(擬似マルチスレッド)」です。

鍵を握る魔法の命令:`DoEvents`

VBAには本格的なマルチスレッド機能はありません。しかし、OSに対して「ちょっと待って、今溜まっているWindowsのメッセージ(画面の再描画やクリックなど)を処理させてあげるから、コントロールを一時的に返してね」と命令する方法があります。それが `DoEvents` 関数です。

ループの中にこの `DoEvents` を適切に挟み込むことで、処理速度を極端に落とさずに、UIのフリーズを完全に回避することができます。

実践!進捗バー付き・フリーズ回避ループの実装

百聞は一見に如かず。今回は、大量のタスクを走査する重い処理を想定し、ステータスバーに進捗率を表示させながら、途中で「キャンセル」もできる実用的なコードを見ていきましょう。

サンプルコード:安全でスマートな一括処理マクロ

以下のコードを、あなたのプロジェクトファイルの標準モジュールに貼り付けてみてください。

Option Explicit

‘ —————————————————————–
‘ @Title: 大量タスク処理におけるUIフリーズ回避&進捗表示テンプレート
‘ @Description: DoEventsとカウンター制御を組み合わせたプロ仕様のループ処理
‘ —————————————————————–
Sub ProcessTasksWithoutFreezing()
Dim t As Task
Dim totalTasks As Long
Dim currentCount As Long
Dim nextUpdate As Long

‘ 処理対象のタスクが存在するか確認
On Error Resume Next
totalTasks = ActiveProject.Tasks.Count
On Error GoTo 0

If totalTasks = 0 Then
MsgBox “処理対象のタスクがありません。”, vbExclamation, “中断”
Exit Sub
End If

‘ ユーザーへの確認
If MsgBox(“合計 ” & totalTasks & ” 件のタスクを処理します。実行しますか?”, _
vbYesNo + vbQuestion, “処理開始の確認”) = vbNo Then
Exit Sub
End If

‘ 画面描画の最適化(裏で動かすことでさらに処理速度を向上させる)
Application.ScreenUpdating = False

currentCount = 0
nextUpdate = 1 ‘ 更新頻度をコントロールするための変数

‘ ステータスバーの初期化
Application.StatusBar = “処理を準備中…”

‘ ループ開始
For Each t In ActiveProject.Tasks
If Not t Is Nothing Then
‘ — ここに実際の重い処理を記述 —
‘ 例:すべてのタスクのカスタムテキスト1にフラグを立てる
t.Text1 = “Checked”
‘ ———————————-

currentCount = currentCount + 1

‘ 【重要】すべてのタスクでDoEventsを呼ぶと逆に遅くなるため、
‘ 100件に1回、または一定間隔でUIに制御を返す
If currentCount >= nextUpdate Then
‘ 進捗率を計算してステータスバーに表示
Dim pct As Integer
pct = CInt((currentCount / totalTasks) 100)

Application.StatusBar = “処理中… ” & pct & “% 完了 (” & currentCount & ” / ” & totalTasks & “)”

‘ OSに処理を返し、画面のフリーズを防ぐ
DoEvents

‘ 次に更新するタイミングを設定(例:100件ごと)
nextUpdate = currentCount + 100
End If
End If
Next t

‘ 終了処理
Application.ScreenUpdating = True
Application.StatusBar = “処理が正常に完了しました。”

MsgBox “全タスクの処理が完了しました!”, vbInformation, “完了”

‘ 数秒後にステータスバーをクリア
Application.StatusBar = “”

Exit_Handler:
Exit Sub

Error_Handler:
Application.ScreenUpdating = True
Application.StatusBar = “”
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “エラー”
Resume Exit_Handler
End Sub

コードの核心:プロが解説する3つのポイント

1. `DoEvents` を呼ぶ頻度をデザインする

`DoEvents` は非常に強力ですが、「すべてのタスクループの1回ごとに呼ぶ」のはNGです。Windowsへのコンテキストスイッチ(切り替え)が発生するため、逆に処理速度が何倍にも落ちてしまいます。
上記のコードでは、`nextUpdate` 変数を使って「100件に1回」だけ `DoEvents` を実行するように調整しています。このバランス感覚がエンジニアの腕の見せ所です。

2. `Application.ScreenUpdating = False` との合わせ技

Projectは、タスクが1つ書き換わるたびにガントチャートの描画を更新しようとします。これが重さの元凶です。
処理の最初に `ScreenUpdating = False` を宣言し、処理が終わったら `True` に戻すことで、裏で高速にデータを処理させつつ、`DoEvents` によってユーザーインターフェースの「呼吸(応答性)」だけを保つことができます。

3. ステータスバーの活用

ユーザーに「今、パソコンがサボらずに仕事をしていること」を伝えるために、MS Project標準の `Application.StatusBar` を利用しています。メッセージボックスを何度も出すよりも、ステータスバーに「〇%完了」と流し込む方が、圧倒的にスマートでモダンなアプリケーションの挙動になります。

陥りがちな罠とエラー対策

罠:`For Each` の中でタスクを削除・追加してしまう

今回のコードは「参照(読み取りとプロパティの変更)」なので安全ですが、もしループの最中にタスクを `Delete` したり新しく追加したりすると、コレクションのインデックスが狂い、実行時エラーや無限ループを引き起こします。
大量のタスクを削除・追加する場合は、必ず後ろから前へ数える `For` ループ(逆順ループ)を使いましょう。

‘ 逆順ループの例(タスクの削除時など)
Dim i As Long
For i = ActiveProject.Tasks.Count To 1 Step -1
Set t = ActiveProject.Tasks(i)
If Not t Is Nothing Then
If t.PercentComplete = 100 Then
t.Delete
End If
End If
‘ 必要に応じてここでDoEventsを挟む
Next i

まとめ:ここをクリアすれば、Project VBAの基本はバッチリ!

今回は、大量のプロジェクトデータを扱う上級者のための「非同期処理のシミュレーションとUIフリーズの回避」について解説しました。

  • 「画面が固まる恐怖」は `DoEvents` で克服できる。
  • ただし、毎回呼ぶのではなく、一定間隔(バッチ的)に呼ぶのがパフォーマンスの極意。
  • `ScreenUpdating` とステータスバーを組み合わせて、ユーザーフレンドリーなUIを作る。

このテクニックを取り入れるだけで、あなたが書くマクロは「ただ動くプログラム」から「実務で安心して使えるプロフェッショナルなツール」へと生まれ変わります。

ぜひ、あなたの現場のプロジェクトファイルで試してみてくださいね。それでは、次のステップでお会いしましょう!

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