こんにちは!プロジェクト管理の現場で、日々数え切れないタスクと格闘していませんか?
「予定通りに進んでいるはずなのに、気づけば遅延タスクが山積みになっていた……」
「Excelなら条件抽出が一撃なのに、MS Projectの画面で毎回フィルターを設定し直すのが面倒くさすぎる!」
そんなフラストレーションを抱えているあなたへ。
今回は、マクロの記録の向こう側へ一歩踏み出し、「VBAで動的にフィルターを生成し、遅延タスクだけを鮮やかに炙り出すレポート自動化手法」を伝授します。
ここをクリアすれば、Project VBAの基本構造やオブジェクトモデルの癖が手に取るように分かるようになりますよ。さあ、一緒にプログラミングの快感に浸りましょう!
—
1. なぜ「マクロの記録」だけでは実務で通用しないのか?
Excel VBAと同じ感覚でMS Projectの「マクロの記録」をポチッと押すと、生成されたコードの長さに絶望した経験はありませんか?
Project VBAの最大の特徴は、「グローバル(またはプロジェクト個別)のオブジェクト辞書(コレクション)を操作する」という点にあります。特にフィルターやグループといったビューの設定は、単に「画面を切り替える」のではなく、「定義(Definition)を作成し、それをビューに適用する」という二段階のライフサイクルを持っています。
手動で行うとマウス操作で数クリックかかる作業も、コードの本質を知れば一瞬です。まずは、今回のミッションの全体像を確認しましょう。
今回のミッション
1. 既存のカスタムフィルターを動的に上書き・作成する(`FilterEdit`メソッドの活用)
2. 「遅延しているタスク(基準日より遅れていて、まだ完了していないもの)」を的確に捉える条件式を組み立てる
3. 作成したフィルターをアクティブビューに適用し、必要に応じて集計・レポート出力の土台を作る
—
2. 【核心】遅延タスク抽出エンジンの全体像
まずは、実務の現場でそのままコピー&ペーストして動かせる完全版のコードをお見せします。標準モジュールに貼り付けて実行してみてください。
Sub CreateAndApplyDelayFilter()
Dim tsk As Task
Dim filterName As String
filterName = “自動抽出:遅延タスク”
On Error GoTo ErrorHandler
‘ 画面描画をロックしてパフォーマンスを極限まで高める(お作法です)
App.ScreenUpdating = False
‘ —————————————————-
‘ Step 1: 既存の同名フィルターが存在すれば削除してクリーンな状態に
‘ —————————————————-
On Error Resume Next
Dim oldFilter As Filter
Set oldFilter = ActiveProject.TaskFilters(filterName)
If Not oldFilter Is Nothing Then
oldFilter.Delete
End If
On Error GoTo ErrorHandler
‘ —————————————————-
‘ Step 2: 動的にフィルターを新規作成する (FilterEdit)
‘ —————————————————-
‘ 引数の意味:
‘ Name: フィルター名
‘ TaskFilter: Trueならタスク用フィルター(Falseならリソース用)
‘ Create: 新規作成ならTrue
‘ ShowInMenu: メニューに表示するか
‘ ShowRelatedSummaryRows: 関連するサマリータスクを表示するか(重要!)
‘ FieldName: 比較するフィールド名(ここでは「バリアンス(開始)」または「終了日」など)
‘ Test: 条件演算子(pjCompareGreaterThan = より大きい など)
‘ Value: 比較する値
‘ —————————————————-
FilterEdit Name:=filterName, _
TaskFilter:=True, _
Create:=True, _
ShowInMenu:=True, _
ShowRelatedSummaryRows:=True, _
FieldName:=”終了日”, _
Test:=pjCompareLessThan, _
Value:=Format(Date, “YYYY/MM/DD”), _
Operation:=pjAnd, _
FieldName2:=”完了”, _
Test2:=pjCompareEquals, _
Value2:=”いいえ”
‘ —————————————————-
‘ Step 3: 作成したフィルターを現在のビューに適用する
‘ —————————————————-
FilterApply Name:=filterName
‘ —————————————————-
‘ Step 4: 抽出された遅延タスクをイミディエイトウィンドウにログ出力
‘ —————————————————-
Debug.Print “=== 【遅延タスク レポート】 実行日: ” & Date & ” ===”
Dim delayCount As Long
delayCount = 0
For Each tsk In ActiveProject.Tasks
‘ サマリータスクやマイルストーンを除外したい場合のガード(今回は実タスクかつフィルター条件に合致するもの)
If Not tsk Is Nothing Then
If tsk.Summary = False And tsk.Active = True Then
‘ 簡易的な遅延判定(終了予定日が今日を過ぎていて、かつ未完了のもの)
If tsk.Finish < Date And tsk.PercentComplete < 100 Then
delayCount = delayCount + 1
Debug.Print "ID: " & tsk.ID & " | タスク名: " & tsk.Name & " | 終了予定: " & tsk.Finish & " | 進捗率: " & tsk.PercentComplete & "%"
End If
End If
End If
Next tsk
Debug.Print "合計遅延タスク数: " & delayCount & " 件"
MsgBox "遅延タスクの抽出とレポート出力が完了しました!" & vbCrLf & "該当件数: " & delayCount & "件", vbInformation, "処理成功"
CleanUp:
App.ScreenUpdating = True
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical, "予期せぬエラー"
Resume CleanUp
End Sub
---
3. コードの急所を解剖する:ここが分かればProject VBAは怖くない
初学者が最もつまずきやすいポイント、そして実務でトラブルになりやすいポイントを3つに絞って解説します。
① `FilterEdit` メソッドの魔力と引数の罠
MS ProjectのVBAにおいて、`FilterEdit` は「GUIでポチポチ設定するダイアログボックスの代行」です。
ここで重要なのは、「1つのフィルターの中に、AND条件やOR条件を複数組み込める」という点。
コード中の以下の部分に注目してください:
FieldName:=”終了日”, Test:=pjCompareLessThan, Value:=Format(Date, “YYYY/MM/DD”), _
Operation:=pjAnd, _
FieldName2:=”完了”, Test2:=pjCompareEquals, Value2:=”いいえ”
- 第1条件: 終了日が本日の日付より前(過ぎている)
- 演算子: `pjAnd`(かつ)
- 第2条件: 完了フラグが「いいえ」(まだ終わっていない)
この2つを組み合わせることで、「過去にスケジュールされていながら、まだ終わっていないタスク=真の遅延タスク」を正確に定義できます。
② `ShowRelatedSummaryRows:=True` の慈悲
プロジェクト管理において、子タスクだけを抽出すると「親タスク(サマリー)のどこに属しているか」が分からなくなり、全体像が迷子になります。
`ShowRelatedSummaryRows:=True` を指定することで、「抽出されたタスクが所属するアウトラインの階層(親サマリー)」を自動的に一緒に表示してくれます。これがないと、現場のマネージャーから「どの工程の遅延か分からない!」と怒られてしまうので、実務では必ず `True` に設定しましょう。
③ 画面描画のロック (`ScreenUpdating = False`)
Projectは、タスクの数が数千件規模になると、フィルターを適用するたびにガタガタと画面の再描画(ビューの再構築)を行います。これが実行速度を劇的に遅くする原因です。
処理の最初に `App.ScreenUpdating = False` を置き、最後に `True` に戻す。この「プロフェッショナルの作法」を入れるだけで、実行スピードが体感で何倍も変わります。
—
4. 現場でよくある「ハマりどころ」と回避策
罠:日本語フィールド名でエラーが出る
MS Projectは、PCのOS言語やOfficeの言語設定によって、内部のフィールド名(英語名)と表示名(日本語名)の厳密なマッピングが揺らぐことがあります。
もし `FieldName:=”終了日”` でエラー(実行時エラー 1101など)が出る場合は、定数(PjField列挙体)を使用するのがエンジニアとしてのスマートな解決策です。
‘ 文字列ではなくPjField列挙体を使う例(確実性アップ)
FieldName:=pjTaskFinishDate
罠:すでに同名のフィルターがあって上書きに失敗する
手動ですでに同じ名前のフィルターを作っていると、`FilterEdit` で新規作成(`Create:=True`)しようとした際に衝突することがあります。
今回のコードの「Step 1」のように、作成前に一度既存の同名フィルターを安全に削除(またはエラーをスルー)する防御的プログラミング(Defensive Programming)を必ず組み込むようにしてください。
—
おわりに:ここをクリアすれば、あなたはもう「中級者」です!
お疲れ様でした!
今回扱った `FilterEdit` と `FilterApply` をマスターすれば、単なる「作業の自動化」を超えて、「プロジェクトの状態を動的に監視・分析するシステム」をMS Projectの内部に構築できるようになります。
「毎回手動でフィルターを作って、エクセルにコピペして……」という不毛な残業とは、今日でサヨナラしましょう。
このコードをベースに、次は「リソースごとの過負荷抽出フィルター」や「今週が期限のクリティカルパス抽出」など、あなたの現場に合わせたアレンジに挑戦してみてください。
あなたのVBAライフが、より知的で圧倒的な成果を生むものになりますように。それではまた、次の極限知見でお会いしましょう!
