こんにちは!Excelマクロの記録から一歩踏み出し、「もっと大規模なスケジュール管理を自動化したい」と、Microsoft ProjectのVBA(Project VBA)の世界に飛び込んできたあなたへ。
今回は、Project VBAの真骨頂であり、多くの開発者が最初に躓く壁――「Excelの平坦なリストから、美しいWBS(Work Breakdown Structure)の階層構造を動的に再構築するアルゴリズム」について徹底解説します。
ここをクリアすれば、Project VBAの基本とオブジェクトモデルの動きが手に取るように分かるようになりますよ。しっかりついてきてくださいね!
—
なぜ、WBSの動的構築で躓くのか?
実務では、「Excelで作成したタスク一覧を、ボタン一つでProjectに取り込みたい」という要望が本当によくあります。
【Excel側のデータ構造(イメージ)】
行 | レベル | タスク名
—————————
1 | 1 | 01. 調査フェーズ
2 | 2 | 01-01. ヒアリング
3 | 2 | 01-02. 要件定義
4 | 1 | 02. 開発フェーズ
これをVBAで単純に「上から順番にタスクを追加していこう」とコードを書くと、大体こんなエラーや不具合に直面します。
- 「インデント(OutlineLevel)の方向がおかしいです」というエラーが出る
- 親タスクと子タスクの親子関係がバラバラになり、ガントチャートが崩壊する
Projectの `Task` オブジェクトには、Excelの行のように「ここが親です」という直接的な親子プロパティを代入するのではなく、「インデントレベル(OutlineLevel)」を操作することで、裏側で自動的にWBSのツリー構造が構築されるという独特の仕様があります。
この仕様を理解し、安全にタスクを積み上げるアルゴリズムをマスターしましょう。
—
押さえておくべきProject VBAの基本思想
Excel VBAとProject VBAの最大の違いは、「オブジェクトの親子関係とコンテキストの重み」です。
1. ActiveProjectの存在
Projectでは、現在アクティブなプロジェクトを `ActiveProject` として操作します。
2. Tasksコレクション
タスクは `ActiveProject.Tasks` というコレクションに順番に蓄積されます。
3. OutlineLevel(アウトラインレベル)
タスクの階層(1が最上位、2がその子、3が孫…)を決定する最重要プロパティです。
陥りやすい罠:急激なレベル上昇エラー
Projectでは、例えばレベル1の直後にいきなりレベル3のタスクを作ろうとすると、システムが「レベル2が抜けている!」と判断し、エラーを吐くか、勝手に辻褄を合わせようとして構造が崩れます。
これを防ぐためには、「前回のタスクのレベルに対して、今回のレベルが許容範囲内か」を制御しながら追加していく必要があります。
—
【実践】ExcelリストからWBSを動的構築するVBAコード
今回は、Excelからデータを読み込み、ActiveProject側にインデントを正確に再現しながらタスクを生成する実用的なコードを用意しました。
このコードは、Project側のVBAエディタ(`Alt + F11` で開く)に標準モジュールを追加して貼り付けて実行することを想定しています。あらかじめExcelが開かれ、特定のシートにデータがある状態を前提としています。
Sub BuildWBSFromExcel()
‘ — 変数の宣言 —
Dim xlApp As Object
Dim xlWb As Object
Dim xlWs As Object
Dim lastRow As Long
Dim i As Long
Dim tskNew As Task
Dim targetName As String
Dim targetLevel As Long
Dim prevLevel As Long
‘ — 1. Excelファイルの参照を取得(※事前にExcelを開いておく想定) —
On Error Resume Next
Set xlApp = GetObject(, “Excel.Application”)
If xlApp Is Nothing Then
MsgBox “Excelが起動していません。対象のExcelを開いてから実行してください。”, vbCritical
Exit Sub
End If
Set xlWb = xlApp.ActiveWorkbook
Set xlWs = xlWb.ActiveSheet
On Error GoTo 0
‘ — 2. 既存のタスクをクリア(※実務では確認を入れるべきですが今回は簡略化) —
‘ 注意:ActiveProject.Tasks.Clear は存在しないため、逆順で削除します
Dim t As Task
For i = ActiveProject.Tasks.Count To 1 Step -1
Set t = ActiveProject.Tasks(i)
If Not t Is Nothing Then t.Delete
Next i
‘ — 3. Excelの最終行を取得してループ処理開始 —
lastRow = xlWs.Cells(xlWs.Rows.Count, “A”).End(3).Row
prevLevel = 1 ‘ 初期レベル
‘ 2行目からデータ開始(1行目はヘッダーと仮定)
For i = 2 To lastRow
targetLevel = xlWs.Cells(i, 1).Value ‘ A列:インデントレベル (1, 2, 3…)
targetName = xlWs.Cells(i, 2).Value T ‘ B列:タスク名
If targetName <> “” Then
‘ タスクを新規追加(一番下に追加されていく)
Set tskNew = ActiveProject.Tasks.Add(Name:=targetName)
‘ 【重要】アウトラインレベルの設定
‘ Projectでは、タスクを追加した後に OutlineLevel を設定する
‘ ※ただし、急激なレベルスキップを防ぐためのガードを入れるのがプロの技
If targetLevel > prevLevel + 1 Then
‘ レベルが不自然に飛んでいる場合は、安全のため「前回のレベル + 1」に補正
targetLevel = prevLevel + 1
End If
‘ レベルの適用
tskNew.OutlineLevel = targetLevel
‘ 次の比較のために現在のレベルを保持
prevLevel = targetLevel
End If
Next i
‘ — 4. 完了メッセージ —
MsgBox “WBSの動的構築が完了しました!”, vbInformation, “処理成功”
End Sub
—
コードの解説:ここがエンジニアのこだわりポイント!
1. タスク追加とレベル設定の順序
Project VBAでは、`ActiveProject.Tasks.Add(Name:=…)` でタスクを追加した瞬間、それはプロジェクトの一番下に追加され、デフォルトでは最上位(レベル1)として認識されます。
その後、間髪入れずに `tskNew.OutlineLevel = targetLevel` を実行することで、Projectが自動的に親タスクを識別し、ツリー構造に組み込んでくれます。
2. レベルスキップのガード処理
If targetLevel > prevLevel + 1 Then
targetLevel = prevLevel + 1
End If
この数行こそが、現場でエラーを出さないための「防衛的プログラミング」です。Excel側の入力ミス(例えば、レベル1の次にいきなりレベル3が書かれているなど)があった場合でも、このガードがあればマクロが途中でクラッシュするのを防ぎ、綺麗に階段状のWBSに収めてくれます。
—
ここをクリアすれば、Project VBAの基本はバッチリですよ!
お疲れ様でした!Excelの平坦なデータを、Project特有の「アウトライン構造」に変換するアルゴリズムの仕組み、イメージできたでしょうか?
- 「タスクを追加する」
- 「OutlineLevelプロパティで階層をコントロールする」
- 「データの整合性を保つためのガードを入れる」
この3つさえ押さえておけば、どんなに複雑な外部システムからのデータ連携であっても、自在にMicrosoft Projectをコントロールできるようになります。
マクロの記録の枠を飛び出し、自分の手でオブジェクトを意図通りに操る爽快感を、ぜひ次の開発でも味わってみてくださいね。あなたの自動化ライフを、これからも応援しています!
