こんにちは!Project VBAの世界へようこそ。
マクロの記録から一歩踏み出し、「現場で本当に使える自動化」をマスターしたいあなたへ。
今回は、実務で絶対に避けて通れない「WBS(階層構造)の再帰的走査と、子タスクからの進捗率の自動集計」をテーマにお届けします。
「親タスクの進捗率を、子タスクの状況に合わせて自動で綺麗にまとめたい」
「でも、階層が何重にも深くなると、コードが複雑になってお手上げ……」
そんな風に悩んだことはありませんか?
大丈夫。ここで紹介する「再帰関数(Recursive Function)」のテクニックをモノにすれば、どんなに複雑なツリー構造であっても、たった数行の美しいアルゴリズムで完全にコントロールできるようになります。
ここをクリアすれば、あなたのProject VBAスキルは間違いなく中級者の域を突破します。さあ、一緒に扉を開けましょう!
—
なぜ「再帰関数」が必要なのか?
MS ProjectのWBSは、親タスクの下に子タスクがあり、さらにその子タスクの下に孫タスクがある……という「ツリー構造(階層構造)」をしています。
[1. プロジェクト全体](親)
┣ [1.1 要件定義](子)
┃ ┣ [1.1.1 ヒアリング](孫)
┃ ┗ [1.1.2 仕様書作成](孫)
┗ [1.2 開発フェーズ](子)
もし、この階層が「最大でも2階層まで」と決まっていれば、`For Each` ループを2回ネスト(入れ子)にすれば集計できます。しかし、実務のWBSは3階層、5階層、あるいはそれ以上に深くなります。階層の深さが変動するたびにコードを書き直すなんて、エンジニアの仕事ではありませんよね。
ここで登場するのが再帰関数です。
再帰関数とは、「自分自身を呼び出す関数」のこと。「親を見たら、その子を見ろ。子を見たら、さらにその孫を見ろ」という処理を、関数が自分自身を再利用しながら自動的に奥へ奥へと潜っていくため、何階層あっても完璧に網羅できるのです。
—
実務で使える!進捗率自動集計スクリプト
それでは早速、実際の開発現場でそのままコピペして使える完全版のVBAコードを公開します。
プロジェクトの標準モジュールに貼り付けて実行してください。
‘ ==============================================================================
‘ プロジェクト名: WBS階層進捗率自動集計ツール
‘ 概要 : タスクツリーを再帰的に走査し、子タスクの工数(Work)を重み付けとして
‘ 親タスクの進捗率(% Complete)をボトムアップで算出・同期します。
‘ ==============================================================================
Sub AutoCalculateParentProgress()
Dim prj As Project
Set prj = ActiveProject
‘ パフォーマンス向上のため、画面描画と警告を一時停止
Application.ScreenUpdating = False
Application.DisplayAlerts = False
On Error GoTo ErrorHandler
‘ ルートレベル(最上位)のタスク群から再帰処理を開始
Dim tsk As Task
For Each tsk Is prj.Tasks
If Not tsk Is Nothing Then
‘ 概要タスク(子を持つ親タスク)かつ、プロジェクトの最上位レベルを起点にする
If tsk.Summary And tsk.OutlineLevel = 1 Then
Call RecurseAndCalculate(tsk)
End If
End If
Next tsk
Application.ScreenUpdating = True
Application.DisplayAlerts = True
MsgBox “WBSの進捗率の自動集計が完了しました!”, vbInformation, “成功”
Exit Sub
ErrorHandler:
Application.ScreenUpdating = True
Application.DisplayAlerts = True
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “エラー”
End Sub
‘ ——————————————————————————
‘ 関数名 : RecurseAndCalculate
‘ 引数 : parentTask (Task) – 走査対象の親タスク
‘ 戻り値 : Double – 計算された子タスク全体の「実績値(進捗×工数)」の総和
‘ 概要 : 再帰的に子タスクを掘り下げ、ボトムアップで進捗率を計算・設定する
‘ ——————————————————————————
Function RecurseAndCalculate(parentTask As Task) As Double
Dim childTask As Task
Dim totalWeightedProgress As Double
Dim totalWork As Double
Dim hasChildren As Boolean
totalWeightedProgress = 0
totalWork = 0
hasChildren = False
‘ 配下の直下の子タスクをループ処理
For Each childTask Is parentTask.OutlineChildren
hasChildren = True
If childTask.Summary Then
‘ 子タスクがさらに親(概要タスク)である場合、再帰的に潜って計算結果を取得する
Dim subTaskWeightedProgress As Double
subTaskWeightedProgress = RecurseAndCalculate(childTask)
‘ 親側の集計値に加算(子タスク自身のWorkを重みとして利用)
totalWeightedProgress = totalWeightedProgress + subTaskWeightedProgress
totalWork = totalWork + childTask.Work
Else
‘ 葉タスク(最下層の実タスク)の場合の計算
‘ 重み付けとして「工数 (Work)」を使用し、進捗率(% Complete)を掛け合わせる
totalWeightedProgress = totalWeightedProgress + (childTask.PercentComplete childTask.Work)
totalWork = totalWork + childTask.Work
End If
Next childTask
‘ 子が存在する場合、重み付け平均(進捗率 = 完了済み工数合計 ÷ 総工数合計)を計算
If hasChildren And totalWork > 0 Then
Dim calculatedPercent As Double
calculatedPercent = totalWeightedProgress / totalWork
‘ 親タスクの進捗率に計算結果を反映させる
parentTask.PercentComplete = calculatedPercent
End If
‘ 呼び出し元へ「この階層の進捗×工数の総和」を返す
RecurseAndCalculate = totalWeightedProgress
End Function
—
コードの核心:ここがポイント!
初学者のうちにつまづきやすいポイントを、先輩エンジニアの視点で解説します。
1. `OutlineChildren` プロパティの威力
MS ProjectのVBAには、あるタスクの「直下の子タスク群」を一発で取得できる `OutlineChildren` という極めて強力なコレクションが用意されています。これを使うことで、「親IDと子IDのインデントレベルを比較して……」といった面倒な判定ロジックを書く必要がなくなります。
2. なぜ「工数(Work)」で重み付けするのか?
実務において、単純な「子タスクの進捗率の平均(例:3つの子タスクの平均だから ÷3)」で親の進捗を出すのはNGです。
- 子タスクA(工数 100時間): 進捗 0%
- 子タスクB(工数 10時間): 進捗 100%
この場合、単純平均すると進捗は `50%` になってしまいますが、工数ベースで重み付けすると `(0100 + 10010) / 110 = 9%` となり、プロジェクトの実態に即した正しい進捗率が算出されます。このコードは実務の現場でそのまま使えるロジックになっています。
3. パフォーマンスの魔法:`ScreenUpdating = False`
プロジェクトのタスク数が数千件規模になると、VBAからタスクのプロパティ(`PercentComplete`など)を書き換えるたびに、画面の再描画やProject内部のスケジュール再計算が走って処理が重くなります。
処理の最初に `Application.ScreenUpdating = False` を挟むことで、バックグラウンドで高速に計算を完結させ、爆速で処理を終わらせることができます(終わるときに `True` に戻すのを忘れないようにしましょう)。
—
陥りやすいエラーと回避の知見
実務でこのコードを運用する際によくある落とし穴と、その対策を共有します。
- エラー:「オブジェクト変数または With ブロック変数が見つかりません」
- 原因: 削除されたタスクや、カスタムフィルタによって予期せぬ `Nothing` がコレクションに含まれている場合に発生します。
- 対策: コード内にある `If Not tsk Is Nothing Then` のような空チェックを必ず挟む防衛的プログラミングを徹底しましょう。
- 「循環参照(Circular Dependency)」の罠
- 原因: タスク間の依存関係(FSやSSなど)で意図せずループが組まれていると、Project全体がフリーズすることがあります。進捗率の計算自体は依存関係を直接書き換えませんが、タスクの親子関係が歪んでいないか、事前にWBSの構造を確認してください。
—
まとめ:Project VBAの基本はバッチリ!
今回は、再帰関数を用いたWBS階層構造の走査と、重み付け進捗率の自動集計について解説しました。
- 階層の深さに依存しない「再帰関数」のアルゴリズム
- 実務で必須となる「工数(Work)による重み付け平均」の考え方
- 大量データを瞬時に処理するパフォーマンス最適化の作法
ここをしっかりと理解できたあなたなら、もう「マクロの記録を貼り付けるだけの初学者」ではありません。自信を持って、現場の業務効率化をリードしていってください。
あなたのProject VBAライフが、より知的でエキサイティングなものになりますように!
