MS Project VBAの深淵:日付を「書き込む」のではなく「エンジンに納得させる」技術
こんにちは!Project VBAの世界へようこそ。
マクロの記録機能を使って、「あ、このボタンを押した時の動きをコードにしたいな」と思うようになったあなたは、もう立派な自動化エンジニアへの第一歩を踏み出しています。
しかし、ここからが本当の勝負です。
Excelのような「セルに値を書き込む」感覚で、MS Projectのタスク開始日(`Task.Start`)を書き換えようとしていませんか?
もしそうなら、少しだけ立ち止まってください。
MS Projectは単なる表計算ソフトではありません。背後で、膨大な計算リソースを消費してスケジュールを整合させる「動的なスケジューリング・エンジン」が常に動いているのです。
今日は、一歩上のエンジニアになるための重要なテーマ、「日付の強制書き込みが引き起こす副作用と、エンジンの制御術」についてお話ししましょう。ここをマスターすれば、あなたの作るツールは「壊れにくい、プロ仕様のシステム」へと進化します。
1. なぜ「日付の書き込み」は危険なのか?
初心者の方が最初につまずくのは、次のようなコードを書いた時です。
' ⚠️ 初心者が陥りやすい、リスクのある書き方
Sub SimpleUpdate()
Dim t As Task
Set t = ActiveProject.Tasks(1)
t.Start = "2023/12/01" ' 直接日付を代入
End Sub
一見、何も問題ないように見えますよね? でも、MS Projectの内部では「事件」が起きています。
エンジンとの衝突(制約条件の自動変更)
MS Projectのタスクには、「できるだけ早く(ASAP)」や「できるだけ遅く(ALAP)」といった制約条件(Constraint Type)があります。
あなたが `t.Start = “2023/12/01″` と直接書き込んだ瞬間、MS Projectはこう判断します。
> 「おっと、ユーザーが日付を指定したぞ。これは『できるだけ早く』というルールよりも、この日付を優先しろという意味だな。よし、制約条件を 『開始日指定(Start No Earlier Than)』 に変更しておこう!」
つまり、あなたの意図とは裏腹に、タスクの性質(制約条件)が勝手に書き換わってしまうのです。これが「副作用」の正体です。一度この制約が付くと、前後のタスクとの関係性(先行・後続関係)が崩れ、スケジュール全体がガタガタになることがあります。
2. 「書き込み」と「再計算」のライフサイクル
プロのエンジニアは、日付を書き換えるとき、以下の3つのステップを意識します。
1. エンジンの停止(計算モードの変更): 書き換えのたびにエンジンが動くと、動作が重くなり、計算ミスも起きやすくなります。
2. データのバッチ書き込み: 必要なデータを一気に流し込みます。
3. エンジンの再起動(再計算のトリガー): 書き換えが終わった後に、「さあ、新しい条件で計算し直してくれ!」と命令します。
これを図解的にイメージするとこうなります。
【ダメな例:毎回計算エンジンが悲鳴を上げる】
`書き込み` $\rightarrow$ `エンジンが計算` $\rightarrow$ `書き込み` $\rightarrow$ `エンジンが計算` …(非効率&不安定)
【プロの例:まとめて流し込んでから計算】
`エンジン停止` $\rightarrow$ `書き込み` $\rightarrow$ `書き込み` $\rightarrow$ `エンジン起動(再計算)`(高速&正確)
3. 実践:副作用を抑えた「プロ仕様」のコード
それでは、実際にどのようにコードを書くべきか見てみましょう。
ここでは、複数のタスクの日付を一括で更新し、最後に正しくスケジュールを再構築するテンプレートを紹介します。
''' <summary>
''' タスクの日付を安全に一括更新するプロフェッショナル・ルーチン
''' </summary>
Sub ProfessionalDateUpdate()
Dim t As Task
Dim targetDate As Date
' 1. 計算モードを「手動」に切り替えて、エンジンを一時停止させる
' これにより、書き込みのたびに再計算が走るのを防ぎ、パフォーマンスを劇的に向上させます。
Application.Calculation = pjManual
On Error GoTo ErrorHandler ' エラーが発生した際の安全装置
' 画面更新を止めてさらに高速化
Application.ScreenUpdating = False
' --- ここからデータ更新処理 ---
' サンプルとして、プロジェクト内の全タスクの開始日を少しずつずらす処理
targetDate = DateAdd("d", 1, Date) ' 明日から開始
For Each t In ActiveProject.Tasks
If Not t Is Nothing Then
' 【重要】直接 Start をいじる前に、制約条件を「できるだけ早く(ASAP)」に戻す
' これにより、日付を書き込んでも「制約によるロック」がかかりにくくなります。
t.ConstraintType = pjAsSoonAsPossible
' 日付を代入
t.Start = targetDate
' 次のタスクのために日付を更新(デモ用)
targetDate = DateAdd("d", 2, targetDate)
End If
Next t
' --- ここまで ---
' 2. エンジンを「自動」に戻し、計算を再実行(トリガー)させる
' これにより、書き換えた日付に基づいて、後続タスクなどが正しく再計算されます。
Application.Calculation = pjAutomatic
' 明示的に再計算を命令(念のための儀式)
Application.Calculate
MsgBox "スケジュールの更新が完了しました!", vbInformation
CleanUp:
' 終了時に必ず画面更新をオンに戻す
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
' エラーが起きても、計算モードが「手動」のままにならないよう、必ず元に戻す
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
Application.Calculation = pjAutomatic
Resume CleanUp
End Sub
コードの解説:ここがプロのポイント!
1. `Application.Calculation = pjManual`:
これが「エンジンの停止」です。大量のタスクを扱う際、これがないと処理時間が数倍〜数十倍変わります。
2. `t.ConstraintType = pjAsSoonAsPossible`:
ここが最も重要な知見です。日付を書き込む直前に、制約を「できるだけ早く」にリセットしています。これにより、MS Projectが勝手に「開始日指定」という強い制約をかけるのを防ぎ、スケジュール全体の柔軟性を保てます。
3. `On Error GoTo ErrorHandler`:
もし途中でエラーが起きてプログラムが止まると、MS Projectが「手動計算モード」のまま固まってしまいます。エラーが起きても必ず「自動計算モード」に戻す設計にするのが、プロの責任感です。
まとめ:エンジンの「声」を聞こう
MS Project VBAを極めるということは、単に命令を出すことではなく、「MS Projectの計算エンジンがどう動きたがっているか」を理解して、そのルールに従うことです。
- 日付を書き込むときは、制約条件(ConstraintType)の変化に注意する。
- 大量更新するときは、計算モード(Calculation)をコントロールする。
- 更新の最後には、必ず再計算(Calculate)を促す。
この3点を守るだけで、あなたの作るマクロの信頼性は格段に上がります。
「なぜかスケジュールが変な動きをするんだよね……」という悩みは、もう過去のものになるはずですよ。
さあ、自信を持ってコードを書いていきましょう。応援しています!
