Project VBAの極意:計算エンジンを「黙らせる」ことで爆速化を実現する技術
こんにちは。プロジェクトの複雑な海を渡るエンジニアの皆さん。
今日は、MS ProjectをVBAで操ろうとして、誰もが一度はぶち当たる「あの壁」についてお話ししましょう。
「マクロを動かしている間、Projectが固まったようになる……」
「タスクが数千件あるプロジェクトだと、処理が終わるまでコーヒーを飲みに行かなきゃいけない……」
もしあなたがそう感じているなら、おめでとうございます。あなたは今、「オブジェクトのライフサイクル」と「計算エンジンの重み」という、プロフェッショナルへの入り口に立っています。
今日は、単にコードを書く段階から脱却し、Projectの心臓部(計算エンジン)をコントロールして、処理速度を劇的に向上させる「上級者の作法」を伝授します。
1. なぜあなたのマクロは「遅い」のか?
まず、敵を知ることから始めましょう。なぜMS ProjectのVBAは、ExcelのVBAに比べて「重い」と感じることが多いのでしょうか?
それは、MS Projectが「極めて厳格な計算エンジン」を持っているからです。
「計算の連鎖(Cascade)」という罠
Excelの場合、セルに値を入力しても、そのセルが他のセルとどう繋がっているかを常に監視し続けるわけではありません(数式が入っていない限り)。
しかし、MS Projectは違います。
例えば、あるタスクの「期間」を1日書き換えたとしましょう。その瞬間、Projectのエンジンは以下のような思考を猛烈なスピードで開始します。
1. 「このタスクの終了日はいつになる?」
2. 「それに続く後続タスクの開始日は?」
3. 「リソースの負荷はどう変わる?」
4. 「クリティカルパスはどこに移動した?」
5. 「プロジェクト全体の終了日は?」
これを、「計算の連鎖(Cascade)」と呼びます。
マクロでループを回して1,000個のタスクのカスタムフィールドを更新しているとき、あなたのコードは「1回の更新ごとに、プロジェクト全体の再計算を1,000回強制している」ことになりかねないのです。これが、処理が遅くなる真の理由です。
2. 戦略的アプローチ:計算エンジンを「バイパス」する
では、どうすればいいのか? 答えはシンプルです。
「作業が終わるまで、計算エンジンを黙らせておく」のです。
具体的には、VBAからProjectの計算モードを「自動(Automatic)」から「手動(Manual)」に切り替えます。これにより、タスクの値を書き換えても、Projectは「あ、今は計算しなくていいんだな」と判断し、再計算をスキップします。
黄金のワークフロー
1. 計算モードを「手動」に設定する
2. 大量のデータ更新を行う(ここが爆速になる!)
3. 計算モードを「自動」に戻す
4. 最後に一度だけ、全計算を実行させる
この「一度だけ計算させる」というステップが、データの整合性を保つための極めて重要な鍵となります。
3. 実践:爆速カスタムフィールド更新テンプレート
それでは、実際のコードを見てみましょう。
単にモードを切り替えるだけでなく、「途中でエラーが起きても、必ず計算モードを自動に戻す」という、プロフェッショナルが必ず実装する「エラーハンドリング」を組み込んだ構成にしています。
''**
'' プログラム名:高速カスタムフィールド更新プロシージャ
'' 概要:計算エンジンを一時的に停止させ、カスタムフィールド(Text1)を高速更新する
''**
Sub FastUpdateCustomFields()
Dim t As Task
Dim startTime As Double
' パフォーマンス計測開始
startTime = Timer
' --- [STEP 1] エラーハンドリングの設定 ---
' 万が一エラーが起きても、計算モードを「自動」に戻すためのトラップを用意します
On Error GoTo ErrorHandler
' --- [STEP 2] 計算モードを「手動」に切り替え ---
' これにより、タスク更新ごとの再計算(連鎖)を防ぎます
Application.Calculation = pjCalculationManual
' 画面更新も止めることで、さらに描画負荷を減らします
Application.ScreenUpdating = False
Debug.Print "処理を開始します..."
' --- [STEP 3] メインの処理(データの書き込み) ---
' ここでは例として、すべてのタスクの Text1 フィールドに
' 「Updated: [日付]」という文字列を書き込みます
For Each t In ActiveProject.Tasks
' タスクが存在しない(空白行)場合はスキップ
If Not t Is Nothing Then
' ここで値を直接書き込みます。
' 計算エンジンが止まっているので、この書き込みは一瞬で終わります。
t.Text1 = "Updated: " & Format(Date, "yyyy/mm/dd")
End If
Next t
' --- [STEP 4] 後処理:計算モードを「自動」に戻し、再計算をトリガーする ---
' 最後に一度だけ自動計算に戻すことで、プロジェクト全体の整合性を整えます
Application.Calculation = pjCalculationAutomatic
Application.ScreenUpdating = True
' 処理時間の表示
MsgBox "完了しました!" & vbCrLf & _
"実行時間: " & Round(Timer - startTime, 2) & " 秒", vbInformation
Exit Sub
ErrorHandler:
' --- [重要] エラーが発生した場合のリカバリ ---
' エラーで止まったまま「手動計算モード」になると、ユーザーが
' プロジェクトを操作できなくなる(計算されない)ため、必ず戻します。
Application.Calculation = pjCalculationAutomatic
Application.ScreenUpdating = True
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
End Sub
4. ここをクリアすれば、Project VBAの基本はバッチリですよ
このテクニックを使いこなすために、覚えておいてほしい「設計の心得」が2つあります。
① 「Formula(数式)」フィールドと「値」の使い分け
Projectのカスタムフィールドには、ユーザーがGUIで「数式」を設定できるものがあります。
もし、`Text1` に数式が設定されている場合、VBAから `t.Text1 = “値”` と書き込んでも、数式が優先されて値が上書きされてしまうことがあります。
- 計算ロジックを保持したい場合: GUIで「数式」を設定し、VBAからはその計算の「元となるデータ」だけを書き込む。
- VBAで完全に制御したい場合: 「数式」は空にしておき、VBAから直接「値」を書き込む。
この使い分けができるようになると、設計の自由度が格段に上がります。
② オブジェクトの生存期間を意識する
上記のコードで `For Each t In ActiveProject.Tasks` としていますが、プロジェクトが巨大な場合、この `t`(Taskオブジェクト)へのアクセス自体もコストになります。
しかし、初心者のうちは「計算モードの切り替え」だけで十分すぎるほどの効果を実感できるはずです。
最後に
いかがでしたか?
「計算エンジンを黙らせる」という手法は、単なるスピードアップのテクニックではありません。「ソフトウェアが裏側で何をしようとしているのか」を理解し、それを制御するという、エンジニアリングの本質的なステップです。
最初はエラーハンドリング(`On Error GoTo`)に抵抗を感じるかもしれません。しかし、ツールを配布したり、業務で使うコードを書いたりする以上、「失敗したときにシステムを元の健全な状態(自動計算モード)に戻す」ことは、プロとしての責任です。
ここをクリアすれば、あなたのProject VBAは「ただ動くもの」から「信頼できる武器」へと進化します。
さあ、自信を持って、次のプロジェクトに挑んでください!応援していますよ。
