【入門編】【初心者向け】VBAで制約条件の情報を一覧出力するレポート生成マクロ – Project VBA解析バイブル

スポンサーリンク
スポンサーリンク

マクロの記録から卒業しよう。Project VBAで「スケジュールの制約」を可視化する技術

こんにちは。現場で自動化の設計図を描いている、あなたの少し先を行くエンジニアです。

Microsoft Projectを使ってスケジュールを管理していて、「あれ? このタスク、なぜか日付が動かないぞ?」と不思議に思ったことはありませんか? もしかしたら、それは誰かが意図的に設定した「制約条件(Constraint)」のせいかもしれません。

「制約条件」は、スケジュールの柔軟性をコントロールする強力な武器ですが、プロジェクトが大きくなると「どこに、どんな制約が隠れているのか」を把握するのが非常に困難になります。

今日は、そんな「見えない制約」をExcelに一覧出力して、進捗会議の資料作成を一瞬で終わらせるレポート生成マクロを一緒に作っていきましょう。

「マクロの記録」ボタンを押す段階から、一歩踏み出して「オブジェクトを操る」感覚を掴んでください。ここをクリアすれば、Project VBAの基本はバッチリですよ。

1. なぜ「制約条件」を一覧化する必要があるのか?

Projectの計算エンジンは、非常に賢いです。通常は、タスク同士の「先行・後続関係」に基づいて、ASAP(できるだけ早く)の論理的なスケジュールを自動計算します。

しかし、そこに「制約条件」というルールが介入すると、計算エンジンの動きが変わります。

  • 「開始前(Start No Earlier Than)」: 「これより前には絶対に進めないで」という指示。
  • 「強制開始(Must Start On)」: 「何があってもこの日に始めて」という強力な指示。

これらがプロジェクト内に散らばっていると、クリティカルパスが意図せず歪んだり、リソースの平準化がうまくいかなかったりします。「なぜこのスケジュールになっているのか」という根拠を、データとして客観的に示すこと。これが、プロのプロジェクトマネージャーに求められるスキルです。

2. 攻略の鍵:Project VBAの「オブジェクト構造」を知る

コードを書く前に、Projectがどのような構造(オブジェクトモデル)になっているかを頭に叩き込みましょう。ここを理解せずにコードを書くのは、地図を持たずに樹海に入るようなものです。

Project VBAの世界は、以下のような階層構造になっています。

1. `Application`(Projectというソフトそのもの)
2.  ┗ `Project`(今開いているプロジェクトファイル)
3.   ┗ `Tasks`(プロジェクトに含まれる全タスクの「集合体」)
4.    ┗ `Task`(個々のタスク。ここが主役!)

今回の目的は、`Tasks`という集合体の中から、一つひとつの`Task`を取り出し、その中の「制約タイプ」と「制約日付」というプロパティ(属性)を読み取ることです。

3. 実践:制約条件レポート生成マクロ

それでは、実際に動くコードを見ていきましょう。
このマクロは、ProjectからExcelを立ち上げ、タスク情報を書き込んでいく仕組みです。

Option Explicit

' ==============================================================================
' プログラム名:ConstraintReportGenerator
' 概要:プロジェクト内の全タスクの制約条件をExcelへ一覧出力する
' 作成者:Legendary Architect
' ==============================================================================
Sub ExportConstraintReport()
    Dim targetProject As Project
    Dim t As Task
    Dim xlApp As Object
    Dim xlWB As Object
    Dim xlSheet As Object
    Dim rowNum As Long
    
    ' 1. 準備:現在のプロジェクトをセット
    Set targetProject = ActiveProject
    
    ' 2. Excelの起動(Late Binding方式:環境を選ばず動かしやすい方法です)
    On Error Resume Next
    Set xlApp = CreateObject("Excel.Application")
    If xlApp Is Nothing Then
        MsgBox "Excelを起動できませんでした。", vbCritical
        Exit Sub
    End If
    On Error GoTo 0
    
    ' Excelを可視化
    xlApp.Visible = True
    
    ' 新しいブックを作成
    Set xlWB = xlApp.Workbooks.Add
    Set xlSheet = xlWB.Sheets(1)
    
    ' 3. Excelのヘッダー(見出し)を作成
    With xlSheet
        .Cells(1, 1).Value = "タスクID"
        .Cells(1, 2).Value = "タスク名"
        .Cells(1, 3).Value = "制約タイプ"
        .Cells(1, 4).Value = "制約日付"
        .Cells(1, 5).Value = "開始予定日"
        
        ' 見出しを太字にする(ちょっとしたプロのこだわり)
        .Range("A1:E1").Font.Bold = True
    End With
    
    rowNum = 2 ' データの書き出し開始行
    
    ' 4. タスクのループ処理(ここがメインエンジンです)
    For Each t In targetProject.Tasks
        
        ' 【超重要】タスクが「Nothing」でないかチェック!
        ' 空白行や削除済みのタスクが混じっていると、ここでエラーが出て止まります。
        If Not t Is Nothing Then
            
            ' Excelに情報を書き込む
            xlSheet.Cells(rowNum, 1).Value = t.ID
            xlSheet.Cells(rowNum, 2).Value = t.Name
            
            ' 制約タイプを分かりやすい文字列に変換して出力
            ' ConstraintTypeは数値(列挙型)なので、そのままでは人間には読めません。
            xlSheet.Cells(rowNum, 3).Value = GetConstraintName(t.ConstraintType)
            
            ' 制約日付を出力
            xlSheet.Cells(rowNum, 4).Value = t.ConstraintDate
            
            ' タスク自体の開始予定日も添えておくと便利
            xlSheet.Cells(rowNum, 5).Value = t.Start
            
            rowNum = rowNum + 1
        End If
    Next t
    
    ' 5. 後処理:見た目を整える
    xlSheet.Columns("A:E").AutoFit ' 列幅を自動調整
    
    MsgBox "レポートの作成が完了しました!", vbInformation
    
    ' オブジェクトの解放(メモリを綺麗にするための作法です)
    Set xlSheet = Nothing
    Set xlWB = Nothing
    Set xlApp = Nothing
End Sub

' ==============================================================================
' 関数名:GetConstraintName
' 引数:constraintType (Integer)
' 戻り値:制約タイプの名称 (String)
' 概要:数値としての制約タイプを、人間が読める言葉に変換する
' ==============================================================================
Function GetConstraintName(ByVal cType As Integer) As String
    Select Case cType
        Case 0: GetConstraintName = "なし (ASAP)"
        Case 1: GetConstraintName = "開始前 (Start No Earlier Than)"
        Case 2: GetConstraintName = "開始後 (Start No Later Than)"
        Case 3: GetConstraintName = "強制開始 (Must Start On)"
        Case 4: GetConstraintName = "強制終了 (Must Finish On)"
        Case 5: GetConstraintName = "終了前 (Finish No Earlier Than)"
        Case 6: GetConstraintName = "終了後 (Finish No Later Than)"
        Case Else: GetConstraintName = "不明な制約"
    End Select
End Function

4. 陥りやすいエラーと、エンジニアの「思考の癖」

このコードを読み解きながら、初心者が必ずと言っていいほど躓くポイントを解説しておきます。ここを知っているだけで、あなたのデバッグ能力は格段に上がります。

① `If Not t Is Nothing Then` の重要性

これが今回のコードの中で最も重要な一行です。
Projectのタスクリストには、見た目上は空白に見えても、内部的に「空のオブジェクト」が存在することがあります。これを確認せずに `t.Name` などにアクセスしようとすると、「実行時エラー ’91’: オブジェクト変数または With ブロック変数が設定されていません」というエラーでマクロが停止します。
「オブジェクトを扱うときは、まずそれが存在するか疑え」。これは鉄則です。

② 列挙型(Enum)の壁

`t.ConstraintType` をそのままExcelに出力すると、「1」や「3」といった数字が出てきます。これはコンピュータにとっては正解ですが、人間にとっては意味不明ですよね。
そこで、`GetConstraintName` という自作の関数(Function)を用意しました。数値を受け取って、言葉に翻訳して返す。この「翻訳レイヤー」を作る習慣が、使いやすいツールを作るコツです。

③ Late Binding(遅延結合)の選択

コード内で `CreateObject(“Excel.Application”)` と書いています。これは「実行時にExcelを探して起動する」という書き方です。
これを使うと、参照設定(ライブラリの登録)をしなくても動くため、他の人にマクロを配る時に「動かない!」というトラブルを防げます。初学者のうちは、この「配布のしやすさ」を意識してみてください。

5. まとめ:ここからあなたの自動化が始まる

お疲れ様でした! これで、プロジェクト内の「制約条件」を瞬時にリスト化する強力な武器を手に入れました。

最初は「コードが長くて難しそう」と感じたかもしれません。でも、分解してみれば「Excelを開く」→「タスクを一つずつ見る」→「情報を書き込む」という、とてもシンプルなステップの積み重ねです。

次にあなたが挑戦すべきは、このリストを元に「特定の制約(例:強制開始)を持つタスクだけを赤字にする」といった機能の追加です。

一歩ずつ、オブジェクトを支配していきましょう。
ここをクリアすれば、Project VBAの基本はバッチリですよ。応援しています!

タイトルとURLをコピーしました