【入門編】VBAによる「プロジェクトカレンダー」の動的生成とタスクへの一括適用 – Project VBA解析バイブル

スポンサーリンク

こんにちは!プロジェクト管理の現場で、Excelマクロに物足りなさを感じ始め、「いよいよMS ProjectのVBA(Project VBA)に手を出してみよう」と踏み出したところですね。素晴らしい挑戦です。

マクロの記録という「安全なゆりかご」を卒業し、オブジェクトの生命線や階層構造を自らのコードでコントロールする領域へようこそ。ここをクリアすれば、手作業で何時間もかかっていたWBSの調整やカレンダー設定が一瞬で終わる、圧倒的な自動化の世界が広がりますよ。

今回は、Project VBAの真髄の一つである「プロジェクトカレンダーの動的生成とタスクへの一括適用(依存関係最適化)」をテーマに、現場でそのまま使える実用コードと共にお届けします。

なぜ「カレンダーの動的生成」が必要なのか?

MS Projectにはデフォルトで「標準」という稼働日カレンダーが用意されていますが、実際のプロジェクトではそう単純ではありません。

  • 「特定の協力会社チームだけ、水曜日が定休日」
  • 「年末年始や特定のプロジェクト固有の特別休日を、全タスクに一括で反映させたい」
  • 「土日だけでなく、特定の土曜日は稼働日にしたい」

これをGUI(画面操作)でポチポチ設定していると、ヒューマンエラーの温床になります。さらに、タスクごとに誤ったカレンダーが割り当てられていると、クリティカルパスの計算(CPM)が狂い、スケジュール全体が崩壊します。

だからこそ、VBAで「カレンダーのマスター」をプログラムから動的に生成し、対象のタスク群へ正確に一括適用する仕組みが実務で必要になるのです。

押さえておくべきProject VBAの基本構造

コードを書く前に、Project VBA特有の「お作法」を確認しておきましょう。Excel VBAと似て非なるポイントがここにあります。

1. ActiveProjectの概念: 現在アクティブなプロジェクトファイルは `ActiveProject` オブジェクトで指し示します。
2. Calendarsコレクション: プロジェクト内のカレンダーはすべてここに格納されています。新しいカレンダーを作るには `ActiveProject.Calendars.Add` を使います。
3. Task.Calendarプロパティ: タスク個別にカレンダーを割り当てる場合は、各 `Task` オブジェクトの `Calendar` プロパティにカレンダー名を代入します(空欄の場合はプロジェクトのデフォルトカレンダーが継承されます)。

実装コード:カスタムカレンダーの動的生成とタスク一括適用

以下のコードは、新規に「プロジェクト特化型カレンダー」を作成し、土日休日の設定に加えて「特定の特別休日」を追加した上で、選択中のタスク群(または特定の条件に合致するタスク)に一括適用するサンプルです。

開発タブのVBE(Visual Basic Editor)を開き、標準モジュールに貼り付けて実行してみてください。

Sub ApplyCustomCalendarToTasks()
Dim prj As Project
Set prj = ActiveProject

Dim targetCalName As String
targetCalName = “シニアアーキテクト特製カレンダー”

Dim targetCal As Calendar
On Error Resume Next
‘ 既に同じ名前のカレンダーが存在するかチェック
Set targetCal = prj.Calendars(targetCalName)
On Error GoTo 0

‘ 存在しない場合は新規作成(標準カレンダーをベースにする)
If targetCal Is Nothing Then
Set targetCal = prj.Calendars.Add(targetCalName)
MsgBox “新しいカレンダー「 ” & targetCalName & ” 」を作成しました。”, vbInformation, “生成完了”
Else
MsgBox “既存のカレンダー「 ” & targetCalName & ” 」を使用します。”, vbInformation, “流用確認”
End If

‘ 【重要】カレンダーの基本設定(例:土日を休日、平日の稼働時間を8:00〜17:00に設定)
‘ DayOfWeek: 1=日曜日, 2=月曜日, … 7=土曜日
With targetCal
‘ 土日を非稼働日に設定
.WeekDays(pjSunday).Working = False
.WeekDays(pjSaturday).Working = False

‘ 平日(月〜金)の稼働時間を設定
Dim i As Integer
For i = pjMonday To pjFriday
With .WeekDays(i)
.Working = True
‘ 勤務時間のクリアと新規設定
.WorkTimes.Clear
.WorkTimes.Add From:=#8:00:00 AM#, To:=#12:00:00 PM#
.WorkTimes.Add From:=#1:00:00 PM#, To:=#5:00:00 PM#
End With
Next i

‘ 【例外休日の追加】プロジェクト固有の全社研修日などを動的に追加
‘ 既存の例外日に重ならないよう注意しつつ追加
.Exceptions.Add Type:=pjExcepTypeWorking, _
Start:=#5/1/2026#, Finish:=#5/1/2026# ‘ 例:メーデーを稼働日にする変則設定の例

.Exceptions.Add Type:=pjExcepTypeNonWorking, _
Start:=#8/13/2026#, Finish:=#8/15/2026# ‘ 例:夏季特別休業日
End With

‘ 【タスクへの一括適用】
‘ ここでは「現在選択されているタスク(Selection.Tasks)」に対して適用します
Dim t As Task
Dim appliedCount As Long
appliedCount = 0

If ActiveSelection.Tasks.Count > 0 Then
For Each t In ActiveSelection.Tasks
‘ サマリータスク(親タスク)やマイルストーンを除外したい場合はここで条件分岐を入れる
If Not t Is Nothing Then
‘ タスク個別のカレンダーとして割り当て
t.Calendar = targetCalName
appliedCount = appliedCount + 1
End If
Next t

MsgBox “選択された ” & appliedCount & ” 件のタスクにカスタムカレンダーを適用しました!”, vbInformation, “処理完了”
Else
MsgBox “タスクが選択されていません。適用したいタスクを選択してから実行してください。”, vbExclamation, “注意”
End If

End Sub

コードのここがポイント! 押さえておきたい技術的知見

1. `On Error Resume Next` による重複ガード
カレンダーの名前が既に存在する場合、`.Add` メソッドは実行時エラーを引き起こします。これをスマートにいなすために、一度オブジェクトを取得してみて、`Nothing` かどうかで新規作成か既存流用かを分岐させるのがプロの常道です。
2. `WorkTimes` コレクションの作法
カレンダーの稼働時間をいじる際、既存の勤務時間が入ったまま `Add` すると重複エラーや予期せぬスケジューリング結果を招きます。必ず `.WorkTimes.Clear` で一度リセットしてから新しい時間を定義するのが鉄則です。
3. `ActiveSelection.Tasks` の活用
プロジェクト全体に無差別に適用するのではなく、ユーザーが今画面で選んでいるタスク(Selection)に対して動的に適用することで、実務で「部分的なスケジュール調整」に使える柔軟なツールになります。

陥りやすいエラーと回避のテクニック

  • エラー: 「この名前は既に使用されています。」

→ カレンダーの作成時に名前の重複チェックを入れていない場合に発生します。上記のコードのように、事前に `Calendars` コレクションを走査するロジックを必ず組み込みましょう。

  • 「カレンダーを適用したのに、タスクの期間(Duration)が変わらない?」

→ MS Projectの仕様上、カレンダーを変更しても、既に固定された入力値(手動スケジュールなど)のタスクは期間が自動再計算されない場合があります。「自動スケジュール(Auto Scheduled)」モードになっているか、あるいはコード実行後にプロジェクト全体の再計算(`CalculateAll`)を挟むことで解消されます。

ここをクリアすれば、あなたはもう「マクロの記録をいじる人」ではなく、「プロジェクトの時間を自在にデザインする自動化エンジニア」です。現場の面倒なスケジュール調整をコードの力でスマートにハックしていきましょう。次のステップへ進む準備はバッチリですね!

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