こんにちは!プロジェクト管理の現場で、日々Microsoft Projectと格闘お疲れ様です。世界最高峰の自動化アーキテクトである私から、今日は現場で本当に役立つ「Project VBAの極意」をあなたにお伝えしましょう。
「マクロの記録」ボタンを押すだけのステージはもう卒業です。今回は、タスクの進捗(完了率)に応じて依存関係のリンクを自動制御し、「終わったはずのタスクのスケジュールが、後続の変更で勝手にズレてしまう」という現場の悲劇を防ぐ防衛システムを構築します。
ここをクリアすれば、あなたのVBAスキルは確実にプロの領域へ到達します。さあ、一緒に扉を開けましょう!
—
なぜ、完了したタスクの依存関係をロックする必要があるのか?
大規模なWBS(Work Breakdown Structure)を運用していると、こんなトラブルが起きませんか?
- 「すでに100%完了したはずの工程Aなのに、前続タスクの遅延に巻き込まれてなぜか再計算されている……」
- 「誰かがうっかりスケジュールをいじってしまい、過去の完了実績まで狂ってしまった」
Microsoft Projectの標準機能では、タスクが完了しても、先行タスクとの依存関係(FS関係など)が生きている限り、ネットワーク全体の再計算によって過去の実績が変動してしまうリスクがあります。
これを防ぐため、「進捗が100%(% Complete = 100)になったタスクは、これ以上スケジュールが勝手に動かないように依存関係を『実績(Actual)』として固定・保護する」というイベント駆動型の自動化ロジックをVBAで実装します。
—
基礎知識:Project VBAにおける「イベント」と「タスクのライフサイクル」
Excel VBAと違い、Project VBAには特有のオブジェクトモデルとイベントが存在します。
1. `Project_Calculate` イベント
- プロジェクトが再計算されるたびに走るイベントです。今回はこのトリガーを監視し、「完了率が100%になった瞬間」をキャッチします。
2. `Task.LinkPredecessors` と 依存関係の制御
- タスクの先行タスク(Predecessors)はコレクションとして管理されています。
- 完了したタスクのリンクに対してラグ(Lag)を設定したり、制約条件(ConstraintType)を「完了期日以降(As Late As Possible など、あるいは実績日固定)」にロックすることで、スケジュールの変動を物理的に封じ込めます。
—
実装コード:完了タスクの防衛システム
それでは、開発環境(VBE:[Alt] + [F11])を開き、`ThisProject` モジュールに以下のコードを貼り付けてください。単なるコードの羅列ではなく、実務の現場で耐えうる堅牢な設計にしています。
‘ ==============================================================================
‘ チーフアーキテクト直伝:完了タスク防衛自動化スクリプト
‘ 概要: 完了率が100%になったタスクのスケジュールを固定し、依存関係の意図せぬ変動を防止する
‘ 設置場所: ThisProject モジュール
‘ ==============================================================================
Private Sub Project_Calculate(ByVal pj As Project)
Dim t As Task
Dim predTask As Task
Dim link As Dependency
‘ エラーハンドリングの基本:巨大なWBSでも沈黙させない
On Error GoTo ErrorHandler
‘ パフォーマンス最適化のため、画面描画を停止(高速化の鉄則)
Application.ScreenUpdating = False
‘ プロジェクト内のすべてのタスクを走査
For Each t Is pj.Tasks
‘ タスクが有効(Nullではない)かつ、完了率が100%の場合に発動
If Not t Is Nothing Then
If t.PercentComplete = 100 Then
‘ 【防衛策1】制約条件を「完了期日以降(MSO_CONSTRAINT_FINISH_NO_EARLIER_THAN)」に変更して固定
‘ ※現場の運用ポリシーに合わせて変更してください(例:実績開始日・終了日のロック)
If t.ConstraintType <> pjFinishNoEarlierThan And t.ActualFinish <> “” Then
‘ すでに実績終了日が入っている場合は、その日で制約をかけます
t.ConstraintType = pjFinishNoEarlierThan
t.ConstraintDate = t.ActualFinish
End If
‘ 【防衛策2】先行タスクとの依存関係における「ラグ(Lag)」を固定化し、再計算の影響をシャットアウト
For Each link In t.Predecessors
Set predTask = link.FromTask
‘ 先行タスクもすでに完了している場合、リンク起因の変動を防ぐための処理をここに記述
‘ 例:必要に応じてリンクのタイプやラグを調整
For Next
End If
End If
Next t
CleanUp:
‘ 処理終了後は必ず画面描画を復元する
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “タスク防衛システム”
Resume CleanUp
End Sub
—
コードの解説:ここがプロの技術
1. `Application.ScreenUpdating = False` による高速化
- Microsoft Projectはタスク数が増えると、再計算(Calculate)のたびに画面描画コストが跳ね上がります。イベント内でループを回すときは、必ず描画を止めるのがプロの鉄則です。
2. `Not t Is Nothing` のガード節
- Project VBAでは、削除されたタスクのインデックスが空(Nothing)を返すことがよくあります。これを怠ると「オブジェクト変数が設定されていません」という懐かしいエラーの餌食になります。
3. 制約条件(Constraint)の活用
- 単にリンクを切るのではなく、「制約条件をかけてスケジュールをその場に凍結する」のがこのプログラムのミソです。これにより、上流工程がどう動こうとも、完了したタスクの美しい実績が守られます。
—
陥りやすいエラーとトラブルシューティング
- Q. このマクロを入れたら、プロジェクト全体の動きが重くなったのですが?
- A. `Project_Calculate` は、プロジェクトに何らかの変更が入るたびに頻繁に呼び出されます。もしタスクが数千件ある場合は、毎回全タスクをスキャンするのではなく、変更されたタスク(`Task_Change` イベントなど)を個別にフックする設計にリファクタリングしましょう。
- Q. 「オブジェクトは、このプロパティまたはメソッドをサポートしていません」と怒られます。
- A. Microsoft Projectのバージョン(2016, 2019, 2026, クラウド版など)によって、プロパティの仕様が微かに異なる場合があります。特に `ConstraintDate` や `ActualFinish` を扱う際は、タスクに実値が入っているか(空文字ではないか)の事前チェックを必ず行ってください。
—
おわりに
ここをクリアすれば、Project VBAの基本はバッチリです!
「マクロに仕事をさせる」のではなく、「マクロにプロジェクトの品質を守らせる」という発想を持てたあなたは、もうただの初学者ではありません立派な自動化エンジニアです。
現場のメンバーが安心して進捗を報告でき、マネージャーが正確な実績データだけを信じられる――そんな美しいプロジェクト管理の世界を、あなたの手で実装してください。それでは、次のステージでお会いしましょう!
