【入門編】タスクの「制約条件」を無視して依存関係を強制的に優先させる一括設定スクリプト – Project VBA解析バイブル

スポンサーリンク

Project VBAの「制約条件」を制圧!依存関係を強制的に優先させる極秘スクリプト

「プロジェクト管理って、思った通りに進まない…」
「タスクの依存関係が、なんだかうまくいかないんだよな…」

こんな悩みを抱えているあなた!
今日は、Microsoft Project VBAの世界で、あなたのプロジェクト管理を劇的に効率化する「制約条件」の裏技をお教えします。

「制約条件」って聞くと、なんだか難しそう?
でも大丈夫!この記事を読めば、あなたもProject VBAマスターへの道を一歩進めます。
マクロの記録から脱却し、もっとパワフルなプロジェクト管理を目指しましょう!

1. Project VBAとは? なぜ「制約条件」に注目するのか?

1.1. Project VBAの世界へようこそ!

まずは、Project VBAの基本からおさらいしましょう。
Project VBAは、Microsoft Projectに組み込まれた強力な開発環境です。
これを使うと、プロジェクトの自動化、カスタマイズ、そして高度な分析が可能になります。

  • VBA (Visual Basic for Applications): Microsoft Office製品に搭載されているプログラミング言語。
  • Project VBA: Microsoft Projectに特化したVBA。Projectのオブジェクト(タスク、リソース、プロジェクトなど)を操作できます。

1.2. プロジェクト管理の「壁」:制約条件と依存関係

プロジェクト管理で最も重要な要素の一つに、「タスクの依存関係」があります。
「タスクBは、タスクAが終わってから開始する」といった関係性ですね。
Projectはこの依存関係を元に、自動でスケジュールを計算してくれます。

しかし、ここで「制約条件」という強力な「壁」が登場します。

  • 開始日固定: 「このタスクは必ずX月Y日に開始!」
  • 終了日固定: 「このタスクは必ずX月Y日に終了!」
  • 期日: 「このタスクはX月Y日までに終わらせる!」

これらの制約条件は、プロジェクトの重要なマイルストーンを守るために役立ちますが、
依存関係と衝突すると、Projectの自動計算を阻害してしまうことがあるんです。

例えば、タスクAの終了日に依存するタスクBがあったとしても、「タスクBの開始日固定」が設定されていると、タスクAが終わってもタスクBは自動的に開始されません。
「あれ?なんでタスクB始まらないんだ?」
「制約条件?依存関係?どっちを優先すればいいの?」
こんな混乱に陥りやすいのです。

1.3. 今日の「極秘スクリプト」が解決すること

そこで、今回ご紹介するスクリプトは、この「制約条件」と「依存関係」の衝突を一括で解決します。
具体的には、

1. 「開始日固定」「終了日固定」「期日」といった制約条件を、一括で「制約なし」に変換します。
2. その後、Projectに依存関係を再計算させます。

これにより、依存関係が正しく反映され、プロジェクトのスケジュールが意図した通りに自動計算されるようになります。
「制約条件」に邪魔されることなく、タスク間の論理的なつながりを最優先させたい場合に、まさに「魔法の杖」となるでしょう。

2. 実践! 「制約条件」を無視して依存関係を強制するVBAスクリプト

さあ、いよいよ実践編です!
このスクリプトは、Project VBAエディタで作成します。

2.1. Project VBAエディタを開く方法

1. Microsoft Projectを開きます。
2. `Alt + F11` キーを押します。
3. 「Microsoft Visual Basic for Applications」ウィンドウが開きます。

2.2. コードを記述する場所

VBAエディタが開いたら、左側の「プロジェクトエクスプローラー」ウィンドウで、
「ThisProject」または「ThisDocument」といった部分をダブルクリックします。
右側に表示されるコードウィンドウに、以下のコードをコピー&ペーストしてください。

2.3. 極秘スクリプト:制約条件一括解除&依存関係再計算

Sub ForceDependencyPriority()

‘============================================================
‘ 極秘スクリプト:制約条件を無視して依存関係を強制優先
‘============================================================

‘ このスクリプトは、プロジェクト内のすべてのタスクに対して、
‘ 「開始日固定」「終了日固定」「期日」といった制約条件を解除し、
‘ 依存関係に基づいたスケジュールの再計算を強制します。

‘ 「制約条件」と「依存関係」が衝突して、
‘ プロジェクトの自動計算がうまくいかない場合に非常に役立ちます。

‘ ■ 実行前の注意点 ■
‘ ・このスクリプトを実行すると、設定されていた制約条件はすべて失われます。
‘ 実行前に、必要な制約条件は別途メモしておくなどの対策を推奨します。
‘ ・処理対象は、現在開いているプロジェクトファイルのみです。
‘ ・万が一の事態に備え、実行前にプロジェクトファイルを保存することをお勧めします。

Dim t As Task
Dim taskCount As Long
Dim originalConstraint As String

‘ 処理開始のメッセージ
MsgBox “プロジェクト内のタスクの制約条件を解除し、依存関係を優先させます。” & vbCrLf & _
“実行するには「OK」をクリックしてください。”, vbInformation, “制約条件解除スクリプト”

‘ ユーザーに確認を求める(念のため)
If MsgBox(“本当にすべてのタスクの制約条件を解除してもよろしいですか?” & vbCrLf & _
“この操作は元に戻せません。”, vbQuestion + vbYesNo, “確認”) = vbNo Then
MsgBox “処理をキャンセルしました。”, vbInformation, “制約条件解除スクリプト”
Exit Sub ‘ 処理を中断
End If

‘ — 制約条件の解除処理 —
On Error Resume Next ‘ エラーが発生しても処理を続行する(例: 削除できないタスクがある場合)

‘ アクティブなプロジェクトのタスクコレクションをループ処理
For Each t In ActiveProject.Tasks
‘ タスクの制約条件が「制約なし」以外の場合に処理を行う
‘ Project.Constraint(Constrained) プロパティは、
‘ 0: 制約なし (pjConstraintNone)
‘ 1: できるだけ早く (pjConstraintAsSoonAsPossible)
‘ 2: できるだけ遅く (pjConstraintAsLateAsPossible)
‘ 3: 開始固定 (pjConstraintMustStartOn)
‘ 4: 終了固定 (pjConstraintMustFinishOn)
‘ 5: 開始固定 (pjConstraintStartOn) ※ Milestoneのみ
‘ 6: 終了固定 (pjConstraintFinishOn) ※ Milestoneのみ

‘ ここでは、特に「開始日固定」「終了日固定」「期日」に相当するものを解除します。
‘ Project.Constraint プロパティは、制約のタイプを整数で返します。
‘ Project.ConstraintDate プロパティは、制約日付を返します。

‘ 念のため、現在の制約条件を記録しておく(デバッグやログ記録用)
‘ originalConstraint = t.Constraint & ” – ” & t.ConstraintDate

‘ 制約条件を「制約なし」(pjConstraintNone = 0)に設定
‘ Task.Constraint プロパティに直接数値を代入することで設定できます。
t.Constraint = pjConstraintNone ‘ 0: 制約なし

‘ 制約日付もクリア(念のため)
‘ Project.ConstraintDate プロパティは、制約日付をDouble型で返しますが、
‘ 制約なしにした場合は、特定の日付ではなくなるため、クリアするのが一般的です。
‘ ここでは、明示的に日付をクリアするのではなく、制約タイプを pjConstraintNone にすることが重要です。
‘ もし、特定の「期日」を解除したい場合は、t.Deadline = Null のような処理も考えられますが、
‘ 制約タイプを pjConstraintNone にすれば、期日も実質的に無視されるようになります。

‘ エラーが発生した場合の処理(例: 削除されたタスクなど)
If Err.Number <> 0 Then
Debug.Print “タスクID: ” & t.ID & ” の制約条件解除中にエラー発生。エラー番号: ” & Err.Number & “, 説明: ” & Err.Description
Err.Clear ‘ エラーをクリア
End If

‘ 処理したタスク数をカウント
taskCount = taskCount + 1
Next t

On Error GoTo 0 ‘ エラーハンドリングを元に戻す

‘ — 依存関係の再計算を強制 —
‘ Project.Recalculate メソッドは、プロジェクト全体のスケジュールを再計算します。
‘ これにより、解除された制約条件の影響を受けずに、依存関係が正しく反映されます。
ActiveProject.Recalculate

‘ 処理完了のメッセージ
MsgBox taskCount & ” 個のタスクの制約条件を解除しました。” & vbCrLf & _
“依存関係に基づいたスケジュールの再計算が完了しました。”, vbInformation, “制約条件解除スクリプト”

End Sub

‘============================================================
‘ 使用できる定数(参考)
‘============================================================
‘ Const pjConstraintNone = 0 ‘ 制約なし
‘ Const pjConstraintAsSoonAsPossible = 1 ‘ できるだけ早く
‘ Const pjConstraintAsLateAsPossible = 2 ‘ できるだけ遅く
‘ Const pjConstraintMustStartOn = 3 ‘ 開始固定
‘ Const pjConstraintMustFinishOn = 4 ‘ 終了固定
‘ Const pjConstraintStartOn = 5 ‘ 開始固定 (Milestone)
‘ Const pjConstraintFinishOn = 6 ‘ 終了固定 (Milestone)
‘============================================================

2.4. コードの解説:魂を込めて紐解きます!

このコードは、一見複雑に見えるかもしれませんが、一つ一つ紐解いていくと、そのロジックがクリアに見えてきます。

  • `Sub ForceDependencyPriority()`:

これは、このVBAコードの「開始点」を宣言しています。`Sub` は「Subroutine」(サブルーチン、つまり一連の処理のまとまり)を意味します。`ForceDependencyPriority` という名前は、このサブルーチンが「依存関係の優先を強制する」という役割を持っていることを示しています。

  • `Dim t As Task`:

`Dim` は「Declare an Integer」(変数を宣言する)の略です。ここでは `t` という名前の変数を、`Task` 型として宣言しています。`Task` 型というのは、Microsoft Projectにおける「タスク」そのものを表すデータ型です。この `t` を使って、個々のタスクにアクセスし、そのプロパティ(属性)を変更していきます。

  • `Dim taskCount As Long`:

`taskCount` という名前の変数を `Long` 型(整数を格納できる型)で宣言しています。これは、後で処理したタスクの数を数えるために使います。

  • `Dim originalConstraint As String`:

`originalConstraint` という名前の変数を `String` 型(文字列を格納できる型)で宣言しています。これは、もしデバッグやログ記録のために、処理前の制約条件を記録しておきたい場合に使います。今回はコメントアウトしていますが、開発時には非常に役立ちます。

  • `MsgBox …`:

これは、ユーザーに処理の開始を通知したり、確認を求めたりするためのダイアログボックスを表示します。`vbCrLf` は改行コードで、メッセージを読みやすくするために使います。

  • `If MsgBox(…) = vbNo Then … Exit Sub`:

これは、ユーザーに「本当に実行しても良いですか?」と確認し、もし「いいえ」が選択されたら、`Exit Sub` でサブルーチンを中断する処理です。誤操作を防ぐための大切なステップです。

  • `On Error Resume Next`:

ここが VBA のエラーハンドリングにおける重要なポイントです!
通常、VBAコードでエラーが発生すると、その時点で処理が停止します。
しかし、`On Error Resume Next` を記述しておくと、エラーが発生しても処理を停止せず、次の行に進んでくれるようになります。
なぜこれが必要かというと、Projectのタスクには、場合によっては制約条件を直接変更できない特殊なタスク(例えば、プロジェクトサマリータスクや、削除されたタスクの参照など)が存在する可能性があるからです。
この行のおかげで、一部のタスクでエラーが発生しても、他のタスクの処理を中断することなく、最後まで実行することができます。

  • `For Each t In ActiveProject.Tasks`:

これが、プロジェクト内のすべてのタスクを一つずつ取り出して処理するためのループ処理です。
`ActiveProject` は、現在開いているMicrosoft Projectのプロジェクト全体を指します。
`Tasks` は、そのプロジェクトに含まれるすべてのタスクの集まりです。
`For Each` は、「~の各々に対して」という意味で、`Tasks` の中にあるタスクを一つずつ、変数 `t` に代入しながらループを繰り返します。

  • `t.Constraint = pjConstraintNone`:

これが、このスクリプトの「心臓部」です!
`t` は現在処理中のタスクを表します。
`.Constraint` は、そのタスクに設定されている「制約条件の種類」を取得したり設定したりするためのプロパティです。
`pjConstraintNone` は、あらかじめVBAで定義されている定数で、「制約なし」という意味です。
この行によって、現在 `t` が参照しているタスクの制約条件が、「制約なし」に強制的に変更されます。
「開始日固定」「終了日固定」「期日」などの制約条件は、この `pjConstraintNone` に上書きされることで解除されます。

  • `taskCount = taskCount + 1`:

ループが一周するたびに(つまり、一つのタスクの処理が終わるたびに)、`taskCount` の値を1増やしています。これで、処理したタスクの総数を把握できます。

  • `If Err.Number <> 0 Then … Err.Clear`:

`On Error Resume Next` を使っている場合、エラーが発生したかどうかは `Err.Number` という特別な変数で確認できます。
`Err.Number` が 0 でなければエラーが発生したことになります。
このブロックでは、エラーが発生した場合に、そのエラー情報をデバッグウィンドウに出力し、`Err.Clear` でエラー情報をクリアしています。これにより、次のループで新しいエラーを正しく検出できるようになります。

  • `On Error GoTo 0`:

ループ処理が終わったら、この行でエラーハンドリングを通常の状態(エラーが発生したら処理を停止する)に戻します。これ以降でエラーが発生した場合は、通常通りエラーメッセージが表示されます。

  • `ActiveProject.Recalculate`:

これも非常に重要な処理です!
制約条件を解除しただけでは、Projectのスケジュールがすぐに自動で更新されるとは限りません。
`Recalculate` メソッドは、Projectに「プロジェクト全体のスケジュールを再計算してください!」と指示するコマンドです。
これにより、解除された制約条件の影響がなくなり、タスク間の依存関係が正しく解釈され、スケジュールが更新されます。
まさに、依存関係を「強制的に優先」させるための最終的な仕上げと言えるでしょう。

  • `MsgBox taskCount & ” 個のタスクの制約条件を解除しました…”`:

すべての処理が完了したことを、ユーザーに分かりやすく伝えるためのメッセージです。

2.5. 実行方法

1. VBAエディタで、先ほど貼り付けたコードを右クリックします。
2. 「Sub/ユーザーフォームの実行」を選択します。
3. 表示されるリストから「ForceDependencyPriority」を選択し、「実行」ボタンをクリックします。
4. 画面の指示に従って「OK」や「はい」をクリックすると、処理が開始されます。

3. 陥りやすいエラーとその回避策

Project VBAを使い始めると、いくつかの「落とし穴」に遭遇することがあります。
ここでは、このスクリプトに関連して起こりうるエラーと、その対処法を解説します。

3.1. エラー1:タスクが見つからない!?

  • 原因:
  • `ActiveProject.Tasks` コレクションは、開いているプロジェクトの「表示されている」タスクのみを対象とする場合があります。
  • あるいは、コードが実行されたタイミングで、タスクのIDなどが変更された場合。
  • (今回のスクリプトでは直接的な原因にはなりにくいですが)タスクIDが不整合になっている。
  • 回避策:
  • `On Error Resume Next` の活用: 今回のスクリプトでは、このエラーを想定して `On Error Resume Next` を入れています。これにより、個々のタスクでのエラーを無視して処理を続行できます。
  • デバッグウィンドウの確認: エラーが発生した場合は、VBAエディタの「表示」メニューから「イミディエイトウィンドウ」(または `Ctrl + G`)を開き、`Debug.Print` で出力されるエラーメッセージを確認しましょう。これにより、どのタスクで問題が起きているか、手がかりが得られます。

3.2. エラー2:「オブジェクトはこの処理をサポートしていません」

  • 原因:
  • 特殊なタスク(例: プロジェクトサマリータスク、概要タスクの特定レベルなど)に対して、制約条件の変更が許可されていない場合に発生することがあります。
  • あるいは、タスクが削除されているのに、ループ処理で参照しようとした場合。
  • 回避策:
  • `On Error Resume Next` の活用: これも `On Error Resume Next` で対応できます。
  • タスクのフィルタリング: より高度な処理としては、`t.OutlineLevel` プロパティなどでタスクの階層レベルを確認し、処理対象から除外する条件を追加することも考えられます。しかし、今回の「制約条件をすべて解除する」という目的を考えると、`On Error Resume Next` でエラーを無視するのが最もシンプルで効果的です。

3.3. エラー3:制約条件が解除されない!

  • 原因:
  • コードの記述ミス(例: `t.Constraint = 0` とすべきところを `t.Constraint = 1` にするなど)。
  • `pjConstraintNone` という定数の値が間違っている(ただし、VBAの標準定数なので、通常はありません)。
  • `ActiveProject.Recalculate` が実行されていない、または正しく実行されなかった。
  • 回避策:
  • コードの再確認: コードを正確にコピー&ペーストしたか、スペルミスがないかなどを再度確認してください。
  • `pjConstraintNone` の値: VBAエディタで `pjConstraintNone` にカーソルを合わせると、その値(通常は 0)が表示されるはずです。これが正しいことを確認してください。
  • `Recalculate` の実行: `ActiveProject.Recalculate` の行がコードの最後の方にあり、その前で処理が中断していないか確認してください。
  • 手動での確認: スクリプト実行後、いくつかのタスクを選択し、タスク情報の「詳細」タブで制約条件が「制約なし」になっているか、手動で確認してみてください。

4. より高度な活用と応用例

今回ご紹介したスクリプトは、「制約条件」を「制約なし」に一括変換するものですが、これを応用することで、さらに強力なツールを作成できます。

4.1. 特定の制約条件のみを解除する

例えば、「開始日固定」のみを解除したい、といった場合です。
`t.Constraint = pjConstraintNone` の部分を、以下のように変更します。

‘ 例: 「開始日固定」(pjConstraintMustStartOn = 3) のみを解除する場合
If t.Constraint = 3 Then ‘ 3はpjConstraintMustStartOn の値
t.Constraint = pjConstraintNone
End If

‘ 例: 「終了日固定」(pjConstraintMustFinishOn = 4) のみを解除する場合
If t.Constraint = 4 Then ‘ 4はpjConstraintMustFinishOn の値
t.Constraint = pjConstraintNone
End If

4.2. 制約条件を一時的に無効化し、後で元に戻す

これは少し複雑になりますが、以下のような流れで実現できます。

1. 制約条件の情報を保存:
スクリプト実行時に、各タスクの現在の制約条件の種類と日付を配列などに保存しておきます。
2. 一括解除:
今回紹介したスクリプトのように、制約条件を「制約なし」に一括で解除します。
3. 依存関係の再計算:
`ActiveProject.Recalculate` を実行します。
4. 元の制約条件を復元:
保存しておいた情報を使って、各タスクの制約条件を元に戻します。
ただし、この「復元」が非常に難しい場合があります。 なぜなら、制約条件を解除して再計算されたスケジュールは、元の制約条件を復元した際に、意図しないスケジュールになる可能性があるからです。
そのため、この「一時的な無効化」は、非常に慎重な設計とテストが必要です。

4.3. 特定のタスク群にのみ適用する

特定のタスク(例: 特定のフェーズに属するタスク、特定の担当者のタスクなど)にのみ、この処理を適用したい場合です。
`For Each t In ActiveProject.Tasks` のループの前に、条件分岐を追加します。

‘ 例: タスク名に「(暫定)」が含まれるタスクのみを処理する場合
If InStr(t.Name, “(暫定)”) > 0 Then
‘ ここに制約条件解除のコードを記述
t.Constraint = pjConstraintNone
End If

5. まとめ:Project VBAでプロジェクト管理の「壁」を乗り越える!

いかがでしたか?
今回は、Microsoft Project VBAを使って、「制約条件」によって阻害されていた「依存関係」を強制的に優先させるためのスクリプトをご紹介しました。

  • 「制約条件」と「依存関係」の衝突は、プロジェクト管理でよくある悩みです。
  • 今回ご紹介したスクリプトは、制約条件を一括解除し、依存関係に基づいたスケジュール再計算を強制します。
  • `t.Constraint = pjConstraintNone` と `ActiveProject.Recalculate` が、このスクリプトの核となる処理です。
  • `On Error Resume Next` を使うことで、予期せぬエラーにも柔軟に対応できます。

このスクリプトは、あくまで「依存関係を最優先させる」ための強力なツールです。
実行する際は、必ず事前にプロジェクトファイルを保存し、制約条件が失われることのリスクを理解した上で行ってください。

Project VBAの世界は、まだまだ奥深く、あなたのプロジェクト管理をさらに効率化・高度化するための可能性に満ちています。
今回学んだ基本的なループ処理やオブジェクト操作を足がかりに、ぜひ色々な自動化に挑戦してみてください。

「ここをクリアすれば、Project VBAの基本はバッチリですよ。」

あなたのプロジェクトが、よりスムーズに、そして成功に近づくことを願っています!
Happy Automating!

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