ようこそ、Project VBAの深淵なる世界へ。
もし君が、数年前に誰かが書いた「動くけれど重い、そして時々止まる」マクロのメンテナンスを任されたのなら……それは不運ではなく、Project VBAの真髄を学ぶ最高のチャンスです。
Microsoft ProjectはExcelやWordとは全く異なる思想で設計されています。ガントチャートの裏側では、複雑なスケジューリング・エンジンが常に「計算」を繰り返しているからです。古いコードが遅い理由は、そのエンジンの動きを阻害しているからに他なりません。
今日は、マクロの記録から一歩踏み出し、現場で「魔法のように速くなった」と称賛されるための、モダンなリファクタリング手法を伝授しましょう。ここをクリアすれば、Project VBAの基本はバッチリですよ。
—
1. なぜ古いProject VBAは「遅い」のか?
古いコードの多くは、「マクロの記録」をベースにしています。
記録機能は「人間が画面上で行った操作」を忠実に再現します。しかし、プログラムにとって「画面を動かすこと」は最も重い作業なのです。
- Select(選択)の多用: `SelectRow` や `SelectTaskField` は画面描画を強制し、速度を著しく低下させます。
- イベントの放置: 1つのタスクを書き換えるたびに、Projectは全体のスケジュールを再計算しようとします。
- 不適切なオブジェクト定義: `Object`型などの曖昧な宣言は、実行時の負荷を増やします。
これらを排除し、「Projectの心臓部(オブジェクトモデル)」に直接アクセスするのがモダン化の第一歩です。
—
2. Project VBAの「4大オブジェクト」を制する
リファクタリングの前に、私たちが操作する対象を整理しましょう。この階層構造を意識するだけで、コードの見通しは劇的に良くなります。
1. Application: Project全体を支配する神。画面更新の停止などを命じます。
2. Project: 個別のプロジェクトファイル(計画書)。複数の計画を開いている場合に重要です。
3. Task: 工程(タスク)。私たちが最も頻繁に触れる主役です。
4. Resource: リソース(人員や設備)。コストや負荷計算の源です。
—
3. 実践:劇的リファクタリング・ビフォーアフター
では、具体的に「遅いレガシーコード」を「高速なモダンコード」に書き換えてみましょう。
【Before】よくある古いスタイルのコード
(タスクの名前を一括で書き換えるだけの処理ですが、非常に重いです)
Sub OldStyleMacro()
‘ マクロの記録でよく見る、画面選択を繰り返すスタイル
Dim i As Integer
SelectBeginning
For i = 1 To ActiveProject.Tasks.Count
SelectRow Row:=i
‘ 選択した行の「名前」を書き換える(遅い!)
SetTaskField Field:=”Name”, Value:=”【更新】” & ActiveSelection.Tasks(1).Name
Next i
End Sub
【After】高速・モダン化したリファクタリングコード
(同じ処理を、プロフェッショナルの手法で書き換えます)
Sub ModernizedTaskUpdate()
‘ — 1. 定義:型を明示してインテリセンス(入力補完)を効かせる —
Dim prj As Project
Dim tsk As Task
‘ — 2. 高速化の儀式:画面更新と自動計算を一時停止する —
‘ これだけで処理速度が数倍から数十倍変わることもあります
Application.ScreenUpdating = False
Application.Calculation = pjManual ‘ 手動計算に切り替え
‘ エラーが起きても設定を元に戻せるようにエラーハンドリングを設置
On Error GoTo ErrorHandler
Set prj = ActiveProject
‘ — 3. 直接アクセス:Selectを使わずオブジェクトを直接ループする —
For Each tsk In prj.Tasks
‘ Project特有の注意点:空白行(Nothing)の判定が必須
If Not tsk Is Nothing Then
‘ プロパティに直接代入。これが最速です。
tsk.Name = “【更新】” & tsk.Name
End If
Next tsk
‘ — 4. 仕上げ:計算を再実行して最新の状態にする —
prj.Recalculate
MsgBox “更新が完了しました!”, vbInformation
CleanUp:
‘ 最後に必ず画面更新と計算設定を元に戻す(重要!)
Application.ScreenUpdating = True
Application.Calculation = pjAutomatic
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Resume CleanUp
End Sub
—
4. プロが教える「ここがポイント!」
① `ScreenUpdating` と `Calculation` の制御
Project VBAにおける最大のボトルネックは「再計算」です。
100個のタスクをループで更新する場合、設定を変えないと 100回スケジュール計算が走ります。これを `pjManual` にすることで、計算を最後に1回だけ(`Recalculate`)に集約できます。
② `Select` は「悪」と心得る
`SelectRow`(行を選択する)は、ユーザーがマウスでクリックするのと同じ動きをPCに強いています。
モダンなコードでは `For Each tsk In ActiveProject.Tasks` のように、対象(Object)を変数に格納して直接操作します。画面を動かさないので、ユーザーの目には一瞬で終わったように見えます。
③ `Nothing` チェックの罠
Projectの `Tasks` コレクションには、ガントチャート上の「空白行」も含まれることがあります。
空白行に対して `tsk.Name` とアクセスするとエラーで止まってしまうため、必ず `If Not tsk Is Nothing Then` でチェックを入れるのが、熟練者の作法です。
—
5. エラーハンドリングの重要性
古いマクロで一番困るのは、途中でエラーが出たときに「画面が固まったまま」になったり「計算が手動のまま」になったりすることです。
上記のモダンコードに盛り込んだ `CleanUp:` セクションの構造を真似してください。
たとえ途中でエラーが起きても、必ず `Application.ScreenUpdating = True` を通るように設計するのが、現場で信頼されるエンジニアの条件です。
結びに代えて
レガシーなコードをリファクタリングすることは、過去のエンジニアとの対話です。
「当時はこの機能を知らなかったんだな」と理解し、それを現代の最適解で塗り替えていく。この積み重ねが、君をProject VBAを掌握するチーフアーキテクトへと成長させます。
まずは、身近にある `Select` を探して、それをオブジェクト変数への代入に書き換えることから始めてみてください。その一歩で、Project VBAの基本はバッチリ掴めますよ。
応援しています。次なる課題があれば、いつでも相談してくださいね。
