こんにちは!プロジェクトマネジメントの現場で、ExcelとMS Projectを行ったり来たりしながら「あぁ、この進捗データを手でポチポチ入力していく作業、なんとかならないものか……」と絶望したことはありませんか?
マクロの記録ボタンを押しても、MS ProjectはExcelのように親切なコードを吐き出してくれません。そもそも「画面がパカパカ切り替わって遅い」「途中でフリーズする気がする」など、Excel VBAの感覚で書くと痛い目をみるのがProject VBAの奥深いところです。
でも、大丈夫。ここをクリアすれば、あなたもMS Projectを意のままに操る自動化エンジニアの仲間入りです。今回は、MS Projectの命である「Taskのカスタムフィールド(TextやNumberなど)」を爆速で一括更新するテクニックを、優しく、そして本質的な知見を交えて解説していきます。
—
1. なぜMS ProjectのVBAは「遅い」と言われるのか?
Excel VBAでセルを一つずつ書き換えるとき、画面がチラついた経験はありませんか? MS Projectはそれの何倍も重いです。
MS Projectの背後には、「スケジュール計算エンジン」という極めて厳格な頭脳が常駐しています。VBAからタスクのデータを1つ変更するたびに、このエンジンが「おっと、このタスクが変わったから、後続のタスクやサマリー(要約)タスクの日程も再計算しなきゃ!」と、裏で大忙しで計算を走らせます。
これを防がずに、数千件あるタスクのカスタムフィールドを愚直にループで書き換えると……コーヒーを飲みに行っても戻ってくる頃にまだ終わっていない、なんて悲劇が起きます。
解決のキーワード:`ScreenUpdating` と計算の制御
大量のデータを流し込むときは、「画面描画を止め、スケジュール計算の負荷をコントロールする」のが、チーフアーキテクトである私からの最初の教えです。
—
2. 実践!カスタムフィールド一括更新スクリプト
それでは、現場で即座に使える実用コードを公開します。
今回は、Excel等の外部データ(あるいはProject内の別データ)から取得した進捗管理コード(例: `Text1`)と、重要度スコア(例: `Number1`)を一括で流し込むシナリオを想定しています。
Sub UpdateTaskCustomFields_HighSpeed()
Dim t As Task
Dim startTime As Double
startTime = Timer ‘ 処理時間計測用
‘ 【重要】パフォーマンス向上のための基本作法
‘ 1. 画面描画を停止し、再描画のオーバーヘッドを消し去る
Application.ScreenUpdating = False
‘ 2. 自動計算モードを一時的に手動にする(※プロジェクトの設計に合わせて調整してください)
‘ Application.Calculation = pjCalculationManual
On Error GoTo ErrorHandler
‘ プロジェクト内の全タスクを巡回
For Each t In ActiveProject.Tasks
‘ 念のため、ゴミタスク(Nothingや要約タスクなど)を除外する場合のガード
If Not t Is Nothing Then
‘ 【注意】概要タスク(プロジェクト名自体の行など)をスキップしたい場合
If Not t.Summary Then
‘ 例として、タスク名に特定のキーワードが含まれる場合にText1を更新
If InStr(t.Name, “【要件定義】”) > 0 Then
t.Text1 = “Phase-1”
t.Number1 = 100
Else
t.Text1 = “Phase-2”
t.Number1 = 200
End: If
‘ ※ここでカスタムフィールド(Text1~30, Number1~20など)に値を代入
‘ 例: t.Text2 = t.Text1 & “_Checked”
End If
End If
Next t
‘ 処理終了後の後始末
Application.ScreenUpdating = True
‘ Application.Calculation = pjCalculationAutomatic
MsgBox “カスタムフィールドの一括更新が完了しました!処理時間: ” & Format(Timer – startTime, “0.00”) & “秒”, vbInformation
Exit Sub
ErrorHandler:
‘ エラー時も確実に画面描画と計算モードを戻す(これ重要!)
Application.ScreenUpdating = True
‘ Application.Calculation = pjCalculationAutomatic
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
End Sub
—
3. コードのポイントと「初心者がやりがちな罠」
上記のコードには、実務で絶対に知っておくべき「エンジニアの知見」が詰まっています。いくつか重要なポイントを解説します。
① `If Not t Is Nothing` というお作法
MS Projectの `ActiveProject.Tasks` コレクションには、削除されたタスクの跡地や、内部的な空スロットが含まれることがあります。これをそのまま `t.Text1` のように触ると、「オブジェクト変数または With ブロック変数が見つかりません」という、VBA特有の冷酷なエラーに直面します。タスクをループさせる時は、このガード句が命綱になります。
② `Application.ScreenUpdating = False` の絶大な効果
これがあるのとないのとでは、実行速度が文字通り「桁違い」になります。人間の目に見えないところでデータを黙々と流し込み、最後にパッと画面を更新させる。これが大量データを扱うVBAの鉄則です。
③ エラーハンドリング(`On Error GoTo`)の義務
もしループの途中で予期せぬエラーが発生し、`ScreenUpdating = False` のままプログラムが止まってしまったらどうなるでしょう? MS Projectの画面がフリーズしたような状態になり、ユーザーはパニックになります。
必ず `ErrorHandler` を用意し、異常終了時でも必ず描画フラグを `True` に戻す配慮を忘れないでください。
—
4. さらに先へ進むあなたへ(応用テクニック)
今回はProject内のタスクを直接ループさせましたが、実際の現場では「Excelの表にある進捗データを、MS Projectのカスタムフィールドにマージしたい」というケースがほとんどだと思います。
その場合は、VBAからExcelを `CreateObject(“Excel.Application”)` でバックグラウンド起動し、Excel側の配列(Array)にデータを一気に読み込んでから、Project側のタスクID(IDプロパティ)をキーにして高速に突き合わせる(Dictionaryオブジェクト等を使う)と、数万行のデータであっても一瞬で同期できるようになります。
ここをクリアすれば、Project VBAの基本はバッチリです!もう手作業による転記ミスに悩まされる夜はありません。ぜひ、あなたの現場の自動化に役立ててください。
それでは、また次回の極限知見でお会いしましょう!
