「マクロの記録」の先へ。Project VBAの心臓部「計算エンジン」を支配する技術
こんにちは。プロジェクト管理の自動化、その深淵へようこそ。
あなたがもし今、「マクロの記録」ボタンを押し、画面上の操作をそのままコードに書き出す段階にいるとしたら……おめでとうございます。あなたは自動化の第一歩を、正しく踏み出しました。
しかし、もしあなたが「なぜか日付が思い通りに動かない」「大量のタスクを更新すると、画面が固まって動かなくなる」「制約条件を入れたはずなのに、計算結果が矛盾している」といった壁にぶつかっているのなら、それはあなたが「Projectの心臓部(計算エンジン)」に触れようとしている証拠です。
Project VBAは、単なる「Excelのようなセル操作」ではありません。それは、膨大な依存関係と制約条件を解く「数理モデルの制御」なのです。
今日は、プロのエンジニアが現場で密かに行っている、`Application.Options` を介した計算エンジンの制御術について、その本質を解き明かしていきましょう。ここをクリアすれば、あなたの作るツールは「ただの記録」から「信頼できるシステム」へと昇華します。
1. なぜ「自動計算」があなたのコードを破壊するのか
Projectを開いているとき、タスクの期間を変えると、後続のタスクがスルスルと動きますよね? これが「自動計算(Automatic Calculation)」です。
初心者の方は、この「便利さ」に頼りがちです。しかし、大規模なプロジェクト(数千タスク規模)をVBAで操作するとき、この自動計算こそが最大の敵になります。
陥りやすい罠:パフォーマンスの崩壊
例えば、1,000個のタスクに対して、ループ処理で一つずつ「期間」を書き換えるコードを書いたとしましょう。
- 自動計算がONの場合:
1個目のタスクを変更 $\rightarrow$ 全プロジェクトの再計算 $\rightarrow$ 2個目のタスクを変更 $\rightarrow$ また全再計算……
結果として、1,000回の全計算が走り、処理時間は指数関数的に増大します。
解決策:計算モードの「サンドイッチ制御」
プロは、処理の開始前に計算を「手動」に切り替え、すべての書き換えが終わった最後に一度だけ「再計算」を実行します。これをサンドイッチ制御と呼びましょう。
' --- 計算エンジンの制御パターン ---
Sub OptimizedTaskUpdate()
On Error GoTo ErrorHandler
' 1. 画面更新を止めて、計算モードを手動(Manual)に切り替える
' これが「エンジンの暴走」を防ぐ鍵です
Application.Options.Calculate = pjManual
' 2. メインの処理(大量のデータ更新)
Dim t As Task
For Each t In ActiveProject.Tasks
If Not t Is Nothing Then
' 例:特定の条件に基づいて期間を変更
t.Duration = t.Duration + 2 * pjDay
End If
Next t
' 3. 最後に一度だけ、エンジンのスイッチを「自動」に戻して再計算させる
Application.Options.Calculate = pjAutomatic
MsgBox "更新が完了しました!", vbInformation
Exit Sub
ErrorHandler:
' エラーが起きても、計算モードが「手動」のまま放置されると
' ユーザーが「Projectがおかしくなった!」と混乱するため、必ず戻す
Application.Options.Calculate = pjAutomatic
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
End Sub
2. 制約条件(Constraints)の正体:ASAPとALAPを操る
次に、多くのユーザーが混乱する「日付が動かない問題」について。
Projectには、タスクの動きを縛る「制約条件(Constraint)」があります。
VBAで `Task.Start` や `Task.Finish` に直接日付を代入しようとしても、そのタスクに「Must Finish On(〇月〇日に終了しなければならない)」という強い制約がかかっていたら、エンジンはあなたの命令を拒絶(無視)します。
プロが理解すべき「制約の強さ」
制約には、エンジンの計算を「強く縛るもの」と「緩やかに従わせるもの」があります。
- pjAsSoonAsPossible (ASAP): 「できるだけ早く」。エンジンの計算結果に身を任せる、最も柔軟な状態。
- pjMustStartOn / pjMustFinishOn: 「必ずこの日に」。エンジンの計算を強制的に上書きする、最も硬直した状態。
あなたがVBAでスケジュールを「最適化」したいなら、まず制約を「緩いもの」に解いてから、日付を操作するのが鉄則です。
実践:制約を動的に制御するコード
Sub ResetAndSetConstraints()
Dim t As Task
Set t = ActiveProject.Tasks(1) ' 対象のタスク
' --- プロのテクニック ---
' 1. まず、既存の「強い制約」を解除して ASAP(できるだけ早く)に戻す
' これをしないと、日付の代入が無視されることがあります
t.ConstraintType = pjAsSoonAsPossible
' 2. その上で、スケジュールを制御する
' 例えば、特定のタスクを「遅らせる」のではなく「制約で固定する」場合
t.Start = DateAdd("d", 7, Date) ' 7日後に開始
t.ConstraintType = pjStartNoEarlierThan ' 「これより前には開始しない」という緩い制約へ
' 3. ALAP(できるだけ遅く)を実現したい場合
' Projectには直接の「ALAP属性」はありません。
' 「制約を外した状態で、後続関係を調整する」のがエンジニアの仕事です。
End Sub
3. まとめ:エンジニアとしての視点
ここまで読んでくれたあなたに、最後に大切なことを伝えます。
Project VBAを扱うとき、あなたは「セルの値を書き換える作業員」であってはなりません。あなたは「プロジェクトの論理構造を設計するアーキテクト」であるべきです。
- パフォーマンスを意識せよ: `Application.Options.Calculate` を使い、計算のタイミングを支配する。
- 論理の矛盾を防げ: `ConstraintType` を理解し、エンジンの「拒絶」を予測する。
- エラーハンドリングを忘れるな: 計算モードを「手動」にしたままエラーで終了させることは、ユーザーの作業環境を破壊する行為です。
「マクロの記録」で得たコードを、今日の知識を使って「整理・再構築」してみてください。それこそが、脱・初級者への最短ルートです。
ここをクリアすれば、Project VBAの基本はバッチリですよ。
さあ、次の自動化へ向かって、素晴らしいコードを書き進めてください!
