【入門編】【上級者向け】カスタムフィールドの数式構文を外部テキストファイルで管理する仕組み – Project VBA解析バイブル

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

【脱・マクロ記録】Project VBAを掌握する極限の知見:カスタムフィールドの数式を「外部管理」して設計のプロになる

こんにちは。現場の設計図(アーキテクチャ)を引くエンジニアのみなさん。
今日は、Microsoft Project VBAの世界へようこそ。

「マクロの記録」を使って、なんとか自動化の第一歩を踏み出した。でも、こう思ったことはありませんか?
「数式をちょっと変えたいだけなのに、毎回VBAのコードを開いて書き換えるのは、なんだかスマートじゃないな……」

その直感、大正解です。
プロフェッショナルの世界では、プログラムの「動き(ロジック)」と「設定値(データ)」を切り離して考えることを「関心の分離」と呼びます。

今回は、カスタムフィールド(TaskやResourceの計算式)をVBAコードの中に直接書く(ハードコーディングする)のではなく、外部のテキストファイルから読み込む仕組みを構築する方法を伝授します。

これができるようになれば、あなたは「ただ動くマクロを作る人」から、「保守性の高いシステムを設計できるエンジニア」へと進化できるはずですよ。

1. なぜ「コードの中に数式を書く」のがいけないのか?

まず、なぜ外部ファイル化が必要なのか、その理由を整理しましょう。ここを理解することが、エンジニアとしての第一歩です。

❌ ハードコーディング(良くない例)

VBAのコード内に直接こう書いている状態です。

' 開発者がコードを書き換えないと、計算式すら変えられない
ActiveProject.Tasks.CustomFields(1).Formula = "[Cost] * 0.1"

これの何が問題か?
1. 改修コストが高い: 「消費税率が変わった」「計算ルールが変わった」というだけで、VBAプロジェクトを開き、コードを修正し、保存し、再配布しなければなりません。
2. ミスを誘発する: 数式の `’`(シングルクォーテーション)一つ忘れただけで、プログラム全体がエラーで止まります。
3. 環境の切り替えができない: 「開発環境ではテスト用の計算式」「本番環境では実業務の計算式」といった使い分けが、コードを書き換えない限り不可能です。

✅ 外部管理(理想の設計)

「VBAは読み込むための『エンジン』に徹し、数式は『設定ファイル』に任せる」 という設計です。

2. 設計図:仕組みの全体像

図解的に説明すると、以下のようなフローになります。

1. 設定ファイル (`formulas.txt`): 「どのフィールドに、どの数式を入れるか」を記述したテキスト。
2. VBAエンジン: テキストファイルを一行ずつ読み込み、解析(パース)する。
3. MS Project: VBAから命令を受け取り、カスタムフィールドに数式を適用する。

これなら、数式が変わってもテキストファイルを書き換えて、マクロを実行するだけで済みます。

3. 実装:プロフェッショナルのコード例

それでは、実際に動くコードを見ていきましょう。
今回は、`FieldIndex|Formula`(フィールド番号と数式の区切りを `|` にする)という形式のテキストファイルを使用します。

ステップ1:設定ファイルを用意する

メモ帳などで、以下のようなファイルを作成し、プロジェクトファイルと同じフォルダに `config_formulas.txt` という名前で保存してください。

1|[Cost]*0.1
2|[Work]/[Duration]*24
3|=IF([Finish]<[Start], "Error", "OK")

*(※1番目のカスタムフィールドには `[Cost]*0.1` を、2番目には `[Work]/[Duration]*24` を入れる、という意味です)*

ステップ2:VBAコードを書く

ここからは、VBAのエディタに以下のコードを貼り付けてください。初心者の方でも理解しやすいよう、丁寧にコメントを添えています。

Option Explicit

''' <summary>
''' カスタムフィールドの数式を外部ファイルから読み込み、Projectに適用するメインルーチン
''' </summary>
Sub ApplyCustomFieldFormulasFromExternalFile()
    Dim fso As Object
    Dim ts As Object
    Dim filePath As String
    Dim lineContent As String
    Dim parts() As String
    Dim fieldIdx As Integer
    Dim formulaStr As String
    
    ' 1. 設定ファイルのパスを指定(マクロ実行ファイルと同じフォルダの config_formulas.txt)
    filePath = ThisWorkbook.Path & "\config_formulas.txt"
    
    ' FileSystemObjectを作成(ファイル操作のプロフェッショナルな道具)
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    ' ファイルが存在するかチェック(これ、現場では必須の作法です!)
    If Not fso.FileExists(filePath) Then
        MsgBox "設定ファイルが見つかりません: " & filePath, vbCritical, "エラー"
        Exit Sub
    End If
    
    ' 2. ファイルを開いて読み込み開始
    On Error GoTo ErrorHandler ' エラーが起きたらErrorHandlerへジャンプ
    Set ts = fso.OpenTextFile(filePath, 1) ' 1 = ForReading
    
    Do While Not ts.AtEndOfStream
        lineContent = ts.ReadLine
        
        ' 空行やコメント行(#で始まる行)をスキップする工夫
        If Trim(lineContent) <> "" And Left(Trim(lineContent), 1) <> "#" Then
            
            ' 区切り文字 "|" で分割
            parts = Split(lineContent, "|")
            
            ' 分割に成功したか(要素が2つあるか)を確認
            If UBound(parts) = 1 Then
                fieldIdx = CInt(parts(0)) ' 左側を数値に変換
                formulaStr = parts(1)     ' 右側を数式文字列として取得
                
                ' 3. MS Projectのカスタムフィールドに適用
                ' Taskのカスタムフィールドに適用する場合の書き方
                ActiveProject.Tasks.CustomFields(fieldIdx).Formula = formulaStr
                
                Debug.Print "適用完了: Field " & fieldIdx & " -> " & formulaStr
            End If
        End If
    Loop
    
    ts.Close
    MsgBox "カスタムフィールドの更新が完了しました!", vbInformation, "成功"
    
    ' 後片付け
    Set ts = Nothing
    Set fso = Nothing
    Exit Sub

ErrorHandler:
    MsgBox "エラーが発生しました。" & vbCrLf & _
           "内容: " & Err.Description, vbCritical, "実行エラー"
    If Not ts Is Nothing Then ts.Close
    Set ts = Nothing
    Set fso = Nothing
End Sub

4. ここが重要!エンジニアとしての「極限の知見」

コードをコピペして動かすだけで終わっては、本当のプロフェッショナルではありません。このコードの裏側にある「重み」を理解しましょう。

① オブジェクトのライフサイクルとエラーハンドリング

上記のコードでは `On Error GoTo ErrorHandler` を使っています。
VBAで外部ファイル(I/O操作)を扱う際、ファイルが別のプログラムで開かれていたり、権限がなかったりして、「予期せぬエラー」が必ずと言っていいほど発生します。
エラーが起きたときに、開いたままのファイル(`ts`)を適切に閉じる(`ts.Close`)処理を入れないと、メモリリークやファイルロックの原因になります。これは現場では致命的なミスになり得ます。

② パフォーマンスの「重み」

`ActiveProject.Tasks.CustomFields(idx).Formula = …` という命令は、実は非常に「重い」処理です。
数式を一つ設定するたびに、MS Projectはプロジェクト全体の再計算(Recalculation)を走らせようとします。
もし、数千行のタスクがあるプロジェクトで、ループの中でこの処理を何度も何度も繰り返すと、画面がフリーズしたようになります。
大規模プロジェクトを扱う場合は、数式設定の後に一度だけ再計算を促す、あるいは設定の順番を工夫するといった配慮が必要になります。

③ `Split` 関数の活用

`Split(lineContent, “|”)` を使って、一行の文字列を「データ」と「数式」に切り分けています。このように、区切り文字(デリミタ)を決めておくことで、複雑な構造のデータも簡単に扱えるようになります。

まとめ:一歩先へ進むあなたへ

いかがでしたか?
「数式をテキストファイルに追い出す」という小さな工夫。しかし、これができるだけで、あなたの作ったツールは「壊れにくく、変えやすい、プロ仕様の道具」へと昇華されます。

「マクロの記録」から卒業し、こうした「設計の考え方」を意識し始めれば、Project VBAの習得スピードは劇的に上がります。

ここをクリアすれば、Project VBAの基本はバッチリですよ。
次は、この数式を読み込んだ後に、特定の条件でタスクの色を変えるといった「動的な制御」にも挑戦してみてくださいね。

応援しています!

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