はじめに:なぜ、あなたのProjectファイルは重くなるのか?
こんにちは!今日もプロジェクト管理と自動化処理、お疲れ様です。
Microsoft Project(以下、MS Project)を日常的に使っていると、「最初はサクサク動いていたのに、プロジェクトが進むにつれてファイルサイズが肥大化し、保存や開く動作がどんどん重くなる…」という現象に直面したことはありませんか?
実はこれ、単に「タスクが増えたから」だけが理由ではないのです。
マクロの記録を使ったり、手動で試行錯誤しながらプロジェクトを編集していると、画面の裏側で以下のような「目に見えないゴミ」が蓄積されていきます。
- 試行錯誤で作った使い捨てのカスタムテーブルやビュー
- 一時的な分析のために作成し、消し忘れた隠しタスク(作業用タスク)
- 適用したまま残った一時フィルタの残骸
MS Projectは、Excelと異なり内部で高度なデータベース構造を持っています。そのため、これらの「定義データ」がファイル内部(`.mpp`)に保持され続け、パフォーマンスをジワジワと蝕んでいくのです。
今回は、この問題を根本から解決するために「ファイルを保存した瞬間に、裏側で不要なデータを全自動で掃除する軽量化スクリプト」をご紹介します。
ここをクリアすれば、Project VBAの基本とイベント制御の概念はバッチリですよ!一緒にマスターしていきましょう。
—
仕組みの図解:保存イベント(ProjectBeforeSave)の活用
今回作成するのは、ユーザーが `Ctrl + S` や「保存」ボタンを押したときに自動で割り込んで実行されるイベント駆動型(Event-Driven)のVBAスクリプトです。
【通常の保存の流れ】
[保存ボタン押下] ───> (そのままファイル書き込み) ───> [保存完了]
▲ ゴミも一緒に保存される!
【本スクリプト導入後の流れ】
[保存ボタン押下] ───> ★ Project_BeforeSave 発動!
│
├─① 一時的な作業タスクを自動検出・削除
├─② 不要なカスタムテーブルを削除
└─③ 表示画面を安全な状態にリセット
│
(軽量化された綺麗なデータ) ───> [保存完了]
手動で毎回クリーンアップ用のマクロを呼び出す必要はありません。「普通に保存するだけ」で、常にファイルが最軽量な状態に保たれる仕組みを作ります。
—
実装手順とVBAコード
それでは、実際のコードを見てみましょう。
今回のコードは、Project VBAのエディタ内にある `ThisProject` モジュール に直接記述します。
配置場所の確認
1. MS Projectを開き、`Alt + F11` でVBAエディタ(VBE)を開きます。
2. 左側のプロジェクトウィンドウにある `ThisProject` をダブルクリックします。
3. 表示されたコードウィンドウに、以下のコードをそのまま貼り付けてください。
Option Explicit
‘ ==============================================================================
‘ イベント処理:プロジェクト保存直前に自動実行される
‘ ==============================================================================
Private Sub Project_BeforeSave(ByVal pj As Project)
‘ 画面描画とアラートを一時停止して処理速度を極限まで高める
Dim originalAlerts As Boolean
originalAlerts = Application.DisplayAlerts
Application.SystemWarnings = False
Application.DisplayAlerts = False
Application.ScreenUpdating = False
On Error GoTo ErrorHandler
‘ クリーンアップ処理の実行
Call PurgeTemporaryTasks(pj)
Call PurgeUnusedCustomTables(pj)
‘ 処理完了後、設定を元に戻す
Application.ScreenUpdating = True
Application.DisplayAlerts = originalAlerts
Application.SystemWarnings = True
Exit Sub
ErrorHandler:
‘ 万が一エラーが発生した場合も、必ず画面更新を再開させる
Application.ScreenUpdating = True
Application.DisplayAlerts = originalAlerts
Application.SystemWarnings = True
MsgBox “保存前のクリーンアップ中にエラーが発生しました: ” & Err.Description, _
vbExclamation, “VBAクリーンアップ警告”
End Sub
‘ ==============================================================================
‘ 処理①:隠し・一時タスクの自動削除
‘ (例:タスク名が “[TEMP]” で始まるものや、特定のフラグが立ったものを削除)
‘ ==============================================================================
Private Sub PurgeTemporaryTasks(ByRef pj As Project)
Dim i As Long
Dim t As Task
‘ 【重要】コレクションから要素を削除する場合は「後ろから前(逆順)」にループする
‘ 前から削除するとインデックス番号がズレてスキップが発生するため
For i = pj.Tasks.Count To 1 Step -1
Set t = pj.Tasks(i)
If Not (t Is Nothing) Then
‘ 条件: タスク名が “[TEMP]” から始まる、または Flag1 が True のものを一時タスクと判定
If Left(t.Name, 6) = “[TEMP]” Or t.Flag1 = True Then
t.Delete
End If
End If
Next i
End Sub
‘ ==============================================================================
‘ 処理②:不要な一時カスタムテーブルの全自動削除
‘ ==============================================================================
Private Sub PurgeUnusedCustomTables(ByRef pj As Project)
Dim tbl As Table
Dim activeTableName As String
‘ 現在使用中のテーブル名は削除できないため、名前を保持しておく
On Error Resume Next
activeTableName = ActiveProject.CurrentTable
On Error GoTo 0
‘ タスクテーブルコレクションをループ
‘ ※一時テーブルには命名ルールとして頭に “tmp_” を付けている想定
For Each tbl In pj.TaskTables
‘ ビルトイン(標準)テーブルではなく、名前が “tmp_” で始まり、
‘ かつ「現在アクティブなテーブル」ではない場合に削除を実行
If Not tbl.BuiltIn Then
If LCase(Left(tbl.Name, 4)) = “tmp_” Then
If tbl.Name <> activeTableName Then
‘ テーブルの削除実行
pj.TaskTables(tbl.Name).Delete
End If
End If
End If
Next tbl
End Sub
—
ここがプロのポイント!コード解説と陥りやすい罠
「マクロの記録」から一歩抜け出すために、上記コードに含まれる3つの重要なプログラミング技術を解説します。
1. 削除ループの「逆順(Step -1)」ルール
タスクの削除処理で `For i = pj.Tasks.Count To 1 Step -1` としている点に注目してください。
コレクション(集合体)から要素を削除する際、`1 To Count`(正順)でループを回してしまうと、1番目のタスクを削除した瞬間に2番目だったタスクが1番目に詰まります。その結果、ループの次ステップで本来削除すべきだった旧2番目のタスクがスキップされてしまうのです。
【正順で削除した場合の失敗例】
[タスク1(TEMP)] [タスク2(TEMP)] [タスク3]
│
削除実行! ───> 残り: [タスク2(TEMP)] [タスク3]
▲
次は index=2 を見るため「タスク3」に飛んでしまい、
「タスク2」の削除がスキップされる!
要素を削除するときは「必ず末尾からカウントダウンして削除する」。これはProject VBAに限らず、全プログラミング共通の重要テクニックです。
2. アクティブオブジェクト保護の原則
MS Projectの仕様上、「現在画面に表示・使用されているビューやテーブル」はVBAから削除できません。無理に削除しようとすると実行時エラーが発生します。
そのため、コード内では `activeTableName = ActiveProject.CurrentTable` で「今開いているテーブル」の名前を取得し、それに該当するものは削除対象から外す(または安全にスキップする)条件分岐を組んでいます。
3. ScreenUpdating による高速化と画面チラつき防止
`Application.ScreenUpdating = False` を記述することで、VBA処理中の画面の再描画を停止しています。
タスクを1文字ずつ消したり、テーブルを破棄する様子が画面にチラチラ表示されるのを防ぐだけでなく、処理スピードを数倍〜数十倍に引き上げる効果があります。
—
運用上のアドバイス:チームで使うための命名ルール
この自動クリーンアップ機能をチーム全体で運用する場合、あらかじめ「ルール」を1つだけ決めておくと非常にスムーズです。
- 一時タスクを作る場合: タスク名の先頭に `[TEMP]` と付ける(例:`[TEMP] 3月度シミュレーション`)
- 一時テーブルを作る場合: テーブル名の先頭に `tmp_` を付ける(例:`tmp_リソース確認用`)
これだけのルールを周知しておけば、メンバーが検証用に作ったデータがそのまま放置され、ファイルサイズを肥大化させる心配は永久になくなります。
—
おわりに:Project VBAを掌握する第一歩
お疲れ様でした!
今回扱った「イベントプロシージャ(保存検知)」「コレクションの安全な逆順ループ」「アクティブ状態の判定」は、Project VBAの中級レベルへステップアップするための最も重要な土台です。
単なる「マクロの記録」では絶対に到達できない、「ユーザーの操作を裏で支え、事故と肥大化を未然に防ぐプロレベルの仕組み」がこれで完成しました。
まずはテスト用のプロジェクトファイルでコードを貼り付け、`[TEMP]` と名付けたタスクが保存時に「スッと消える快感」をぜひ体験してみてください。
ここをクリアできたら、Project VBAの基本はバッチリです!自信を持って次のステップへ進んでいきましょう。応援しています!
