こんにちは!Project VBAの世界へようこそ。
マクロの記録から一歩抜け出して、「本物のシステム開発」に挑むあなたへ、今日はとてもエキサイティングなお話をしましょう。
Excel VBAなら触ったことがあるという方も多いと思いますが、Microsoft ProjectのVBAは、一味も二味も違います。なぜなら、Projectには「タスクの順序」「依存関係(先行・後続)」「カレンダー」という、時系列の厳格な制約が存在するからです。
今回は、実務で誰もが頭を悩ませる「タスクの挿入・削除に伴うインデックスズレと依存関係の崩壊」を、イベントハンドラを使って完全に自動防御する、上級者向けの極限テクニックを伝授します。
ここをクリアすれば、あなたのProject VBAのスキルは間違いなくプロの領域に到達します。さあ、一緒に扉を開けましょう!
—
1. なぜタスクの「挿入・削除」は魔境なのか?
ProjectでWBS(Work Breakdown Structure)を組んでいるとき、こんな経験はありませんか?
- 「タスク3とタスク4の間に、新しい割り込みタスクを挿入したら、下の行の前提条件(リンク)がめちゃくちゃになった…」
- 「不要になったタスクを削除したら、後続タスクのID(ID番号)がズレてしまい、マクロが予期せぬタスクを操作して大惨事になった…」
Excelの行削除とは違い、Projectのタスクには「ID(通し番号)」と「ユニークID」という2つの顔があります。さらに、タスク同士が「先行・後続」の糸でガチガチに結ばれています。
人間が手動で直すのも大変ですが、これをVBAで制御しようとすると、タスクを挿入・削除した瞬間にインデックスが変わり、コードが迷子になってエラーを吐く……これがProject VBAの「魔境」と呼ばれる理由です。
救世主は「Applicationイベント」だ
この問題を解決するためには、ユーザーがタスクを操作した「その瞬間」を検知し、裏側で自動的に整合性を保つ仕組みが必要です。それが、Projectの「Applicationイベント」です。
—
2. 基礎知識:Projectのイベント駆動型プログラミング
通常のVBAマクロは、あなたがボタンを押したときや、手動でマクロを起動したときにしか動きません。しかし、「イベントプロシージャ」を使えば、Project上で何らかのアクション(ファイルを開く、タスクを追加するなど)が起きたときに、裏で自動的にVBAを走らせることができます。
準備するモジュールたち
Project VBAでイベントを扱うには、少し特殊な準備が必要です。
1. クラスモジュール(例:`EventClass`): イベントを受け取る専用のアンテナを作ります。
2. 標準モジュール(例:`Module1`): アンテナの電源を入れる(イベントを有効化する)コードを書きます。
この仕組みを構築できれば、ユーザーがどんなに激しくタスクを挿入・削除しても、VBAが常に目を光らせて守ってくれます。
—
3. 【実践】インデックスズレを完全回避する監視システムの構築
それでは、実際に動くコードを書いていきましょう。開発現場でそのままコピペして検証できるように、丁寧にコメントを入れています。
ステップ1:イベントを受け取る「クラスモジュール」の作成
VBAのプロジェクトエディタで、新しいクラスモジュールを追加し、名前を `EventClass` に変更してください。そして以下のコードを貼り付けます。
‘ =================================================================
‘ クラスモジュール名: EventClass
‘ 役割: Projectのタスク操作イベントをキャッチし、整合性を守る
‘ =================================================================
Public WithEvents PrjApp As Application
‘ タスクが削除された瞬間に発火するイベント
Private Sub PrjApp_OnTaskDelete(ByVal ASDoc As Document, ByVal ID As Long, ByVal UniqueID As Integer)
On Error GoTo ErrorHandler
‘ 【重要】削除された瞬間のインデックスズレに対する防衛策
‘ タスクが消えたことで、後続のタスクIDが繰り上がります。
‘ ここでログの記録や、依存関係が切断されたタスクの検出を行います。
Debug.Print “タスク削除検知: 削除されたタスクの旧ID = ” & ID
‘ 実務向け:ここで独自の依存関係チェック関数を呼び出す
‘ Call CheckAndRepairDependencies(ASDoc)
Exit Sub
ErrorHandler:
MsgBox “OnTaskDelete イベント内でエラーが発生しました: ” & Err.Description, vbCritical
End Sub
‘ タスクが新しく追加された瞬間に発火するイベント
Private Sub PrjApp_OnTaskEdit(ByVal ASDoc As Document, ByVal Task As Task, ByVal Field As PjField)
‘ ※Projectの仕様上、新規行の挿入はフィールド編集を伴うためここでキャッチ可能
If Field = pjTaskName Then
‘ タスク名が入力された=実質的に新しいタスクが確定した瞬間
‘ ここでデフォルトの前提条件を自動付与するなどの処理が可能です。
End If
End Sub
ステップ2:イベントの電源を入れる「標準モジュール」の作成
次に、標準モジュールを新規作成し、以下のコードを記述します。このコードを実行することで、先ほどのクラスモジュールが常時監視状態に入ります。
‘ =================================================================
‘ 標準モジュール名: Module1
‘ 役割: イベント監視のON/OFFを制御する
‘ =================================================================
Public Watcher As EventClass
‘ 監視をスタートするマクロ
Sub StartProjectWatcher()
If Watcher Is Nothing Then
Set Watcher = New EventClass
Set Watcher.PrjApp = Application
MsgBox “Projectのタスク監視システムが起動しました。”, vbInformation, “システム稼働”
Else
MsgBox “監視システムはすでに稼働中です。”, vbExclamation
End If
End Sub
‘ 監視をストップするマクロ
Sub StopProjectWatcher()
Set Watcher = Nothing
MsgBox “Projectのタスク監視システムを停止しました。”, vbInformation, “システム停止”
End Sub
—
4. 陥りやすいエラーと、プロのエンジニアが教える回避の極意
このシステムを組み込むにあたり、初学者が必ずと言っていいほどハマる「罠」があります。それを事前に知っておくだけで、開発スピードが何倍も跳ね上がります。
罠1:イベントの「無限ループ(連鎖爆弾)」
イベントハンドラの中で、タスクのプロパティ(例えば `Task.Start` や `Task.Name`)を書き換えるとどうなるでしょうか?
「プロパティを書き換える」→「それが新たな編集イベント(`OnTaskEdit`)を引き起こす」→「さらにコードが走る」 という悪夢の無限ループに突入し、Projectがフリーズします。
【回避の極意】
イベント内でタスクを操作・修正する場合は、必ず一時的にイベントの感度を落とす、あるいは「フラグ変数を立てて多重発火を防ぐ」ガードを必ず組み込んでください。
‘ 【無限ループ防止の基本イディオム例】
Private isProcessing As Boolean
Private Sub PrjApp_OnTaskEdit(ByVal ASDoc As Document, ByVal Task As Task, ByVal Field As PjField)
If isProcessing Then Exit Sub ‘ すでに処理中なら抜ける
isProcessing = True
‘ — ここに安全な処理を書く —
‘ Task.Text1 = “自動処理済み”
isProcessing = False
End Sub
罠2:オブジェクトのライフサイクルを意識せよ
`Public Watcher As EventClass` という変数は、Projectを閉じたり、VBAのエラーでコードがリセット(実行時エラーによる中断)されると、メモリから消滅(Nothingに)してしまいます。
「さっきまで動いていたのに、エラーが出たらイベントが反応しなくなった!」という場合は、大抵これが原因です。実運用では、ファイルのオープン時(`Auto_Open` や `Workbook_Open` に相当するイベント)に自動で `StartProjectWatcher` を走らせる仕組みを作っておくと完璧です。
—
まとめ:ここをクリアすれば、Project VBAの基本はバッチリ!
今回は、Project VBAの最難関の一つである「タスク操作時のインデックスズレとイベント監視」について解説しました。
- タスクの挿入・削除はIDのズレを生むため、インデックス直接指定は危険。
- Applicationイベント(`WithEvents`)を使えば、ユーザーの操作にリアルタイムで連動できる。
- イベント内の処理では「無限ループ」に細心の注意を払う。
この領域をマスターしたあなたなら、もはや「マクロの記録を貼り付けるだけの人」ではありません。組織のプロジェクト管理を自動化し、数千行のWBSをも意図どおりに操る「優秀な自動化エンジニア」です。
ぜひ、あなたの手元のProjectでこのコードを試してみてください。ここをクリアできれば、Project VBAの基本はもうバッチリですよ!次のステップへ進みましょう。
