【入門編】プロジェクト開始日の変更に伴う全タスクの「開始日固定」制約の自動解除と再配置 – Project VBA解析バイブル

スポンサーリンク

こんにちは!Excelのマクロ(VBA)は触ったことがあるけれど、「Microsoft ProjectのVBA(Project VBA)」の世界に足を踏み入れた途端、勝手が違って戸惑っていませんか?

「マクロの記録」ボタンを押してもコードがほとんど記録されない。オブジェクトの階層構造が複雑で、どこから手をつけていいか分からない……。そんな壁にぶつかっている方も多いはずです。

でも、安心してください。ここをクリアすれば、Project VBAの基本はバッチリですよ!

今回は、現場で誰もが一度は頭を抱える「プロジェクト開始日の変更に伴う、全タスクの『開始日固定』制約の自動解除と再計算」という実用的なテーマを、優しく、そして本質的な知見を交えて徹底解説します。

なぜ、プロジェクトの日程変更でスケジュールが崩れるのか?

プロジェクト管理を行っていると、「クライアントの都合で全体開始日が2週間後ろ倒しになった!」なんて変更は日常茶飯事ですよね。

Microsoft Project(以下、Project)には、タスクの日程を自動計算してくれる優秀なエンジン(スケジューラ)が備わっています。しかし、現場の担当者が個別に入力したタスクに「これ以上早く始まらない(ASAP)」「指定日開始(SNET)」といった「制約(Constraint)」がガチガチに設定されていると、親であるプロジェクトの開始日を変更しても、子タスクが元の位置に置き去りにされてしまいます。

結果として、スケジュール全体がぐちゃぐちゃに崩壊するわけです。

これを手動で全タスク一件一件「制約なし(ASAP)」に直していくのは、気の遠くなる作業です。――そう、こんな時こそProject VBAの出番です!

Project VBAの基本と「タスクのライフサイクル」

まず、Excel VBAとProject VBAの最大の違いを知っておきましょう。
Excelが「セル(Cell)」の集まりであるのに対し、Projectは「タスク(Task)」の階層構造(WBS)」の集まりです。

Project VBAを操る上で、絶対に押さえておかなければならない鉄則がこれです。

> 【極限の知見:Project VBAの鉄則】
> Project内のすべてのタスクは、`ActiveProject.Tasks` という巨大なコレクション(集合体)の中に生きています。しかし、ここには「削除されたタスクのゴミ」や「サマリータスク(親タスク)」も含まれています。
> ループを回すときは、必ず `Not t Is Nothing`(オブジェクトが存在するか)`t.Summary`(親タスクではないか) を判定しなければ、予期せぬ実行時エラーやバグの温床になります。

実装コード:一括解除・再配置マクロ

それでは、開発環境(VBAエディタ:`Alt + F11`)を開き、標準モジュールに以下のコードを貼り付けてみてください。

現場でそのままコピペして使える、堅牢なエラーハンドリング付きの実用コードです。

Sub ResetConstraintsAndReschedule()
Dim t As Task
Dim targetDate As Date
Dim unlockedCount As Long

‘ 1. ユーザーに新しいプロジェクト開始日を入力してもらう
On Error GoTo CancelHandler
targetDate = InputBox(“新しいプロジェクトの開始日を入力してください(例: 2023/12/01)”, “プロジェクト日程スライド”, Date)
On Error GoTo 0

‘ 2. 処理前の確認
If MsgBox(“全タスクの制約を「できる限り早く(ASAP)」に変更し、” & vbCrLf & _
“プロジェクト開始日を ” & targetDate & ” に再設定しますか?”, _
vbYesNo + vbQuestion, “実行確認”) = vbNo Then
Exit Sub
End If

‘ 3. プロジェクト全体の開始日を更新
‘ ※ProjectオブジェクトのProjectStartプロパティを変更します
ActiveProject.ProjectStart = targetDate

unlockedCount = 0

‘ 4. 全タスクを巡回するループ処理
For Each t In ActiveProject.Tasks
‘ ゴミ(Nothing)や、親タスク(Summary=True)、マイルストーンを除外する判定
If Not t Is Nothing Then
If Not t.Summary Then

‘ 【重要】制約タイプを「できる限り早く(pjConstraintASAP = 0)」に変更
‘ これにより、固定された鎖からタスクを解放します
t.ConstraintType = pjConstraintASAP

‘ 解除した件数をカウント
unlockedCount = unlockedCount + 1

End If
End If
Next t

‘ 5. スケジュールの再計算を実行(Projectに再計算を強制する)
CalculateAll

‘ 6. 完了メッセージ
MsgBox “処理が完了しました!” & vbCrLf & _
“解除・再配置されたタスク数: ” & unlockedCount & ” 件”, _
vbInformation, “成功”

Exit Sub

CancelHandler:
‘ InputBoxでキャンセルされた場合のエラーハンドリング
MsgBox “処理がキャンセルされました。”, vbInformation, “終了”
End Sub

コードのポイント解説

初心者の方でも迷わないよう、コードの核心部分を噛み砕いて解説します。

1. `ActiveProject.ProjectStart = targetDate`
プロジェクト全体の「大元の時計」の針を進める(または戻す)命令です。ここを変更することで、スケジュール全体の基準日が動きます。

2. `t.ConstraintType = pjConstraintASAP`
ここが今回のテーマの心臓部です。「ASAP(As Soon As Possible)」とは、日本語で「できる限り早く」。つまり、前工程が終われば可能な限り早く開始するという、Project本来の「自動スケジュール」の基本状態に戻す制約タイプです。これを代入することで、個別設定されていた面倒な固定制約がすべて綺麗にリセットされます。

3. `CalculateAll`
コードによってタスクの制約を外した直後は、画面上のスケジュール表示がまだ追いついていないことがあります。このメソッドを最後に呼び出すことで、Projectのエンジンに強制的に全タスクの再計算を行わせ、正しいカレンダー・依存関係に基づいた配置にビシッと整えさせます。

陥りやすいエラーと回避のコツ

Project VBAを書くとき、多くの人が次のような罠にハマります。

  • 罠1:「オブジェクトが必要です」というエラーが出る
  • 原因: 削除されたタスクの番号(ID)の残骸や、メモリ上の空白を `For Each` が踏んでしまっています。
  • 対策: 必ず今回のコードのように `If Not t Is Nothing Then` で実体が存在するかチェックしてください。
  • 罠2:親タスク(サマリー)の制約を変えようとして怒られる
  • 原因: Projectの仕様上、親タスクの期間や開始日は子タスクの集計値によって自動決まるため、親の制約を直接いじろうとするとエラーになります。
  • 対策: `If Not t.Summary Then` を使い、個別の作業タスク(末端のタスク)だけに処理を限定しましょう。

まとめ

いかがでしたでしょうか?
「マクロの記録」では絶対に手に入らない、オブジェクトの性質を理解した上でのコード操作。これをマスターすれば、何百・何千行もある巨大なWBSのスケジュール変更も、たった1秒で、しかもミスなく完了させることができます。

ここをクリアしたあなたなら、もうProject VBAの初級者卒業です。ぜひ明日の実務で試してみてくださいね。あなたのエンジニアライフを、心から応援しています!

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