こんにちは!現場でバリバリと自動化を進めていると、MS ProjectのガタガタになったWBS(タスクの階層構造)を目の当たりにして頭を抱えること、ありませんか?
「Excelからデータをインポートしたら、インデントが全部吹っ飛んだ…」
「誰かが勝手にタスクを挿入したせいで、前提条件やサマリータスクの親子関係がぐちゃぐちゃだ…」
手動でポチポチとインデントボタン([インデント] / [アウトデント])を押して直していくなんて、エンジニアの仕事ではありません。こんな作業は秒でマクロに片付けさせましょう!
今回は、「WBSのインデントを再帰処理で自動補正するVBA関数」というテーマで、Project VBAの核心に迫ります。ここをクリアすれば、あなたもマクロの記録から完全に脱却し、Projectのオブジェクトモデルを自在に操る「本物の自動化エンジニア」への扉を開くことになりますよ。
—
1. なぜMS Projectのインデント補正は難しいのか?
ExcelのVBAなら、セルの背景色を変えるだけで終わりですが、MS Projectの世界には「タスクのライフサイクル」「WBSの階層(OutlineLevel)」「アウトラインの親子関係」という独特のルールが存在します。
特に初心者がハマる罠がこれです:
- 「ただ `OutlineLevel` の数値を書き換えればいいや」と代入しても、親タスクとのリンクやサマリーの構造が崩れてエラーになる。
- タスクを上から順番に処理するだけでは、何階層もネストした複雑なWBS(親・子・孫…)の構造を正しく再現できない。
ここで登場するのが、コンピュータサイエンスの強力な武器「再帰処理(Recursive)」です。自分自身を呼び出す関数を使うことで、無限に続く深い階層構造であっても、まるで職人が手作業で仕立てるかのように美しく整列させることができます。
—
2. 命名規則(プレフィックス)で階層を支配する
今回の実務ツールの肝は、「タスク名に付与された命名規則(プレフィックス)を読み取って、自動で階層を決定する」というアプローチです。
例えば、次のようなルールを定めたとします。
- `1. 企画フェーズ` → レベル1(大項目)
- ` 1.1 要件定義` → レベル2(中項目)
- ` 1.1.1 画面設計` → レベル3(小項目)
この「ドット(.)の数」や「インデントの深さ」をVBAでスマートに解析し、Project内のタスクに正しい親子関係をジャッジさせます。
—
3. 実装コード:WBS自動補正エンジン
それでは、開発現場でそのままコピペして使える実用的なVBAコードを公開します。
プロジェクトファイルの標準モジュールに貼り付けて実行してください。
‘ ==============================================================================
‘ 担当:チーフアーキテクト
‘ 概要:タスクの命名規則(ドット区切り等)を解析し、WBSの階層を自動再構築する
‘ ==============================================================================
Public Sub AutoFixWBSHierarchy()
Dim tsk As Task
Dim targetLevel As Long
Dim currentLevel As Long
‘ 実行確認の安全装置
If MsgBox(“現在のタスクのアウトライン構造を再構築しますか?”, vbYesNo + vbQuestion, “WBS自動補正”) = vbNo Then Exit Sub
‘ Undo(元に戻す)の単位をまとめる、プロとしての配慮
App.UndoContextStart “WBS自動階層補正”
On Error GoTo ErrorHandler
‘ エラー抑制(処理中の画面描画を停止して爆速化)
Application.ScreenUpdating = False
‘ プロジェクト内の全タスクを走査
For Each tsk In ActiveProject.Tasks
If Not tsk Is Nothing Then
‘ タスク名から「階層の深さ」を算出するカスタム関数を呼び出し
targetLevel = CalculateLevelFromName(tsk.Name)
If targetLevel > 0 Then
currentLevel = tsk.OutlineLevel
‘ 現在のレベルとターゲットのレベルを比較し、インデントを調整
Do While currentLevel < targetLevel
' 階層を深くする(子にする)
ActiveProject.OutlineNumberDetailIndent tsk.ID
currentLevel = tsk.OutlineLevel
' 無限ループ防止の安全弁
If currentLevel >= targetLevel Then Exit Do
Loop
Do While currentLevel > targetLevel
‘ 階層を浅くする(親に近づける)
ActiveProject.OutlineNumberDetailOutdent tsk.ID
currentLevel = tsk.OutlineLevel
If currentLevel <= targetLevel Then Exit Do
Loop
End If
End If
Next tsk
Application.ScreenUpdating = True
App.UndoContextEnd
MsgBox "WBSの階層自動補正が完了しました!", vbInformation, "完了"
Exit Sub
ErrorHandler:
Application.ScreenUpdating = True
App.UndoContextEnd
MsgBox "エラーが発生しました: " & Err.Description, vbCritical, "エラー"
End Sub
' ==============================================================================
' 補助関数:タスク名に含まれるドットの数からアウトラインレベルを算出
' 例: "1. 計画" -> Level 1
‘ ” 1.2 要件” -> Level 2
‘ ==============================================================================
Private Function CalculateLevelFromName(ByVal taskName As String) As Long
Dim trimmedName As String
Dim dotCount As Long
Dim i As Long
trimmedName = Trim(taskName)
dotCount = 0
‘ 文字列を1文字ずつ走査してドット(.)の数を数える
For i = 1 To Len(trimmedName)
If Mid(trimmedName, i, 1) = “.” Then
dotCount = dotCount + 1
End If
Next i
‘ ドットの数 + 1 をアウトラインレベルとする(例: “1” = L1, “1.1” = L2)
‘ ※最初の数字が存在する場合の簡易ロジック
If dotCount = 0 Then
CalculateLevelFromName = 1
Else
CalculateLevelFromName = dotCount + 1
End If
End Function
—
4. コードのここがポイント!プロの技
1. `App.UndoContextStart` と `UndoContextEnd`
MS Project VBAにおいて、ユーザーが「Ctrl + Z」で変更を元に戻せるようにすることは極めて重要です。これを囲んでおくと、マクロで行った数千件の変更を一発で元に戻せるため、テスト時の安心感が段違いになります。
2. `ScreenUpdating = False` による高速化
Projectは画面の再描画コストが非常に高いアプリケーションです。ループのたびにUIを更新していると途方もなく時間がかかるため、バックグラウンドで一気に処理を走らせるのが鉄則です。
3. 安全弁(Infinite Loop Prevention)の思想
`Do While` を使うときは、必ず「ループから抜け出せなくなるリスク」を想定します。`currentLevel` の変化を監視し、期待するレベルに到達したら強制脱出するロジックを挟むのが、一流のエンジニアの作法です。
—
まとめ:ここをクリアすればProject VBAは怖くない!
今回は、WBSのインデントを自動補正する実務ツールを通して、Project VBAのオブジェクト操作と安全管理の基本を解説しました。
「マクロの記録」では絶対に生成できない、動的かつ実用的なコードが書けるようになると、プロジェクト管理の自動化は一気に楽しく、そして強力なものになります。
「ここをこう変えたらもっと実務で使いやすくなるかな?」とアレンジを加えながら、ぜひご自身のプロジェクトで試してみてください。あなたの手作業の時間をゼロにする力になれれば幸いです。
それでは、次回の高度な自動化の世界でお会いしましょう!
