こんにちは!Microsoft Projectの裏側でうごめくVBAの深淵へようこそ。
今回は、Project VBAにおける「最難関の壁」の一つ、タスクの制約条件(ConstraintType)の動的変更とスケジュール再計算の制御についてお話しします。
「マクロの記録」でコードを取ってみたものの、いざ実務の大量データで動かしたらスケジュールがグチャグチャに崩壊した……そんな苦い経験はありませんか?
大丈夫。ここをクリアすれば、あなたも単なるマクロの利用者から、プロジェクトエンジニアリングをコードで操る「上級プロ」の仲間入りです。一緒に本質を紐解いていきましょう!
—
1. なぜ「ConstraintType」の変更でスケジュールが崩壊するのか?
Excel VBAの感覚でMicrosoft Projectのオブジェクトを触ると、痛い目を見ます。
Excelは「セルの数値を書き換えるだけ」の受動的なキャンバスですが、MS Projectは「生きたエンジン(計算エンジン)」が常に背後で稼働しています。
私たちが `Task.ConstraintType` を変更してタスクの縛り(「できるだけ早く」「〇月〇日以降に開始」など)を変えた瞬間、Projectの計算エンジンはその変更を検知するたびにスケジュールを再計算しようとします。
これが何を意味するか?
1000件のタスクの制約をループでガリガリ書き換えるコードを書いたとします。すると、1回書き換えるごとにプロジェクト全体の再計算が走り、処理が重くなるだけでなく、意図しない依存関係の連鎖で納期が勝手にズレていくという大惨事が起きるのです。
—
2. 【極意】計算エンジンの暴走を止める「手動計算モード」
このカオスを防ぐ唯一にして最大の解決策。それは、「VBAを実行している間は、プロジェクトの自動計算を一時停止させる」ことです。
MS Projectには、アプリケーション全体の計算モードを切り替えるプロパティがあります。
それが `Application.Calculation` です。
これを一時的に「手動(Manual)」に切り替え、コードの最後で一気に「自動(Automatic)」に戻して爆速で再計算させる。これが、プログラミング界の重鎮たちが使っている鉄則テクニックです。
基本的なアーキテクチャ
Sub SafeConstraintChanger()
‘ 1. 計算をマニュアル(手動)モードに変更
App.Calculation = pjCalcManual
‘ 2. 安全な環境下で一括処理を実行
‘ …(ここに制約変更のロジック)…
‘ 3. 計算モードを元に戻し、一斉に再計算を実行
App.Calculation = pjCalcAutomatic
End Sub
ここをクリアすれば、Project VBAの挙動は見違えるほど安定します。
—
3. 実践!安全に制約条件を書き換えるプロダクションコード
それでは、実務でそのまま使える堅牢なコードを公開しましょう。
今回は、「プロジェクト内のすべてのタスク(または特定条件のタスク)の制約を『できるだけ早く (As Soon As Possible: ASAP)』に変更しつつ、スケジュール破綻を防ぐ」プロシージャです。
Sub MasterConstraintControl()
Dim tsk As Task
Dim originalCalc As Long
‘ エラーハンドリングの準備(途中でマクロが落ちても計算モードが戻るようにする)
On Error GoTo ErrorHandler
‘ 1. 現在の計算モードを退避し、手動モードに切り替え
originalCalc = Application.Calculation
Application.Calculation = pjCalcManual
‘ 2. 処理開始のメッセージ
MsgBox “計算エンジンをロックしました。制約条件の一括変更を開始します。”, vbInformation, “Project VBA 制御室”
‘ 3. アクティブプロジェクトのタスクをループ処理
For Each tsk In ActiveProject.Tasks
‘ サマリータスク(親タスク)やマイルストーンを除外するなどの条件分岐
If Not tsk Is Nothing Then
If Not tsk.Summary Then
‘ 例として、すべての通常タスクの制約を「できるだけ早く (ASAP)」に変更
‘ ※pjConstraintASAP は 0 です
tsk.ConstraintType = pjConstraintASAP
‘ 必要に応じて制約日時をクリア(ASAPの場合は日付不要)
‘ tsk.ConstraintDate = “1984/01/01” ‘ 必要に応じて
End If
End If
Next tsk
‘ 4. 計算モードを自動に戻す(ここで一括再計算が走ります)
Application.Calculation = originalCalc
MsgBox “すべての制約変更とスケジュール再計算が正常に完了しました!”, vbInformation, “完了”
Exit Sub
ErrorHandler:
‘ 万が一エラーで止まった場合でも、計算モードが手動のまま放置されるのを防ぐ
Application.Calculation = originalCalc
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “異常終了”
End Sub
コードの重要ポイント解説
- `On Error GoTo ErrorHandler` の絶対死守: 万が一ループ内でエラーが発生した際、計算モードが手動のまま固定されてしまうと、ユーザーが泣くことになります。必ずエラー時にも元の計算モードに戻す保険をかけましょう。
- `Not tsk Is Nothing`: Project VBAでは、削除されたタスクのインデックスが空っぽ(Nothing)であることが稀によくあります。これを弾くのがプロの条件分岐です。
- `If Not tsk.Summary Then`: サマリータスク(親タスク)の制約を無理やりコードでいじるとスケジュールエンジンが大混乱を起こします。実務では子タスク(リーフタスク)のみを対象にするのが鉄則です。
—
4. 陥りやすい罠とエラー対策
罠1:制約日付(ConstraintDate)との矛盾
例えば、`ConstraintType` を「指定日以降に開始 (Start No Earlier Than: SNET)」に変更したにもかかわらず、`ConstraintDate` に空の値や過去の無効な日付が入っていると、Projectはエラーを吐くか、タスクを勝手に現在日に引き戻します。
制約タイプを変更する際は、必ずセットで適切な日付(`ConstraintDate`)を渡しているかを確認してください。
罠2:リンク(先行・後続関係)との喧嘩
タスクAに「〇月〇日以降に開始」という強い制約(SNET)をかけた上で、先行タスクBとの間に「終了-開始 (FS)」のリンクがある場合、スケジュールエンジンは「リンクの計算結果」と「制約条件」のどちらを優先すべきか迷子になることがあります。
プログラムで一括変更する前に、そのタスクが持つネットワーク図上の依存関係に矛盾がないか、あらかじめロジックで担保しておく視点が必要です。
—
まとめ:ここをクリアすれば、Project VBAの基本はバッチリです!
今回は、`ConstraintType` の動的変更におけるスケジュールの再計算制御について解説しました。
1. MS Projectの背後には「生きた計算エンジン」がいることを意識する。
2. 大量処理の前後では `Application.Calculation` を使って手動モードで挟み撃ちにする。
3. サマリータスクの除外やエラーハンドリングを怠らない。
この3つさえ押さえておけば、どんなに巨大なWBSが相手でも、あなたの書いたマクロが暴走することはもうありません。
現場のスケジュール管理をスマートに自動化し、周囲をうならせる美しいVBAコードを書いていきましょう。それでは、また次の深淵でお会いしましょう!
