魂のProject VBA:ガントチャートを支配する「フォント色」動的制御の極意
Microsoft Project(以下、MS Project)を用いたプロジェクト管理において、「状況の可視化」は成否を分ける生命線です。進捗率(% Complete)や遅延状況に応じて、タスクの文字色を動的に変化させる――。一見、Excel VBAなら数行で書けるこの処理ですが、MS Project VBAで実装しようとした瞬間、多くの開発者が深い奈落に突き落とされます。
「なぜ `Task.FontColor = vbRed` のような直感的なコードが動かないのか?」
「なぜタスク数が増えた途端に、マクロがフリーズするのか?」
本稿では、MS Projectのオブジェクトモデルに潜む「致命的な罠」を解き明かし、実務に耐えうる堅牢で極限まで高速化されたプロダクションコードを提示します。Excelの延長線上ではない、真のProject VBAの設計思想をその手に掴んでください。
—
1. MS Projectにおける「書式設定」の特殊性と構造的罠
Excel VBAに慣れ親しんだ開発者が最初に犯す過ちは、「タスク(Task)オブジェクト自体がフォント色のプロパティを持っている」という誤解です。
決定的な違い:データと表現の分離
MS Projectの設計思想において、`Task` オブジェクトは純粋な「スケジュール・実績データ」のみを保持します。文字色や背景色といった「書式(プレゼンテーション)」は、Taskオブジェクトではなく、現在表示されている「ビュー(View)」や「テーブル(Table)」に依存しています。
つまり、以下のようなコードはMS Projectには存在しません。
‘ 存在しないプロパティ(コンパイルエラーまたは実行時エラー)
ActiveProject.Tasks(1).Font.Color = pjRed
ビュー操作コマンド `Font32Ex` の真実
MS Projectで文字色を変更するには、`Application.Font32Ex` メソッド(または従来の `FontEx`)を使用します。
これは「現在アクティブなビューで選択されているセル(または行)」に対して書式を適用するコマンド型(手続き型)のメソッドです。
ここに最大の罠があります。
1. アクティブビュー依存:画面上にタスクが表示されており、かつ選択(Select)されていないと色を変えられない。
2. フィルターの罠:非表示(折りたたまれたサマリータスクの中身や、フィルターアウトされたタスク)のフォントを変更しようとすると、選択できずにエラーを吐くか、全く関係のない別のタスクの色が変わる。
3. 選択処理(SelectRow)のオーバーヘッド:1行ずつ選択して色を変えるため、画面更新を適切に制御しないと絶望的に動作が遅くなる。
この特性を理解せずして、実務で動く堅牢なツールを作ることは不可能です。
—
2. 堅牢な設計:バグを排除するための3原則
実務で破綻しないコードを設計するためには、以下の3つの原則を厳守する必要があります。
原則①:画面描画(ScreenUpdating)と自動再計算の制御
MS Projectはタスクのリンク(依存関係)を常にバックグラウンドで計算しています。1行選択するたびに再計算と再描画が走ると、100タスクを超えたあたりで実用不可能になります。処理開始時にこれらを徹底的に停止させます。
原則②:非表示タスク・サマリータスクの完全な除外
折りたたまれているタスクや、フィルターで隠されているタスクに対して `SelectRow` を実行すると、予期せぬ行が選択され、データが汚染されます。コード内で「そのタスクが現在ビュー上に展開されているか」を判定するか、安全にスキップするロジックを組み込みます。
原則③:ユーザーの選択状態の復元
マクロ実行後に、ユーザーが選択していた行やセルが勝手に変わっているツールは、一級のシステムとは言えません。実行前の選択位置(ActiveCell)を退避し、処理終了後に必ず元の位置へフォーカスを戻します。
—
3. 極限のプロダクションコード:進捗状況による動的フォント色制御
以下に、実務でそのまま使用できる極めて堅牢なコードを示します。
このコードは、各タスクの進捗率(PercentComplete)およびステータスを評価し、以下のように色を動的に変更します。
- 未着手(0%)かつ開始予定超過:赤(警告)
- 進行中(1%〜99%):青(進行中)
- 完了(100%):薄グレー(処理済みとして視認性を下げる)
- 通常(オンスケジュールの未着手):自動(デフォルトの黒)
Option Explicit
”’
”’ ビュー依存のバグを回避し、高速に処理を実行します。
”’
Public Sub ApplyTaskColorByProgress()
Dim appProject As MSProject.Application
Set appProject = MSProject.Application
‘ 1. アクティブプロジェクトの存在確認
If appProject.ActiveProject Is Nothing Then
MsgBox “アクティブなプロジェクトが開かれていません。”, vbCritical, “エラー”
Exit Sub
End If
Dim pj As MSProject.Project
Set pj = appProject.ActiveProject
‘ 2. 現在のビューが「タスクを扱うビュー」であるか確認
Dim currentView As MSProject.View
Set currentView = appProject.ActiveView
If currentView.Type <> pjViewGantt And currentView.Type <> pjViewTaskSheet Then
MsgBox “Ganttチャートまたはタスクシートビューで実行してください。”, vbExclamation, “警告”
Exit Sub
End If
‘ パフォーマンス最適化:画面更新と再計算の停止
On Error GoTo ErrorHandler
appProject.ScreenUpdating = False
Dim originalCalculation As Boolean
originalCalculation = pj.Calculation
pj.Calculation = False
‘ 3. 現在の選択状態(ユーザーのフォーカス)を保存
Dim originalTaskID As Long
On Error Resume Next
originalTaskID = appProject.ActiveCell.Task.ID
On Error GoTo ErrorHandler
‘ 4. 全タスクを走査して色を判定・適用
Dim t As MSProject.Task
Dim rowNumber As Long
rowNumber = 1
‘ ビュー上の行を走査するため、SelectRowを使用する
‘ MS Projectでは、行インデックスは1から始まる
Dim totalRows As Long
totalRows = pj.Tasks.Count
‘ 一旦、選択を先頭行に移動
appProject.SelectRow Row:=1, RowRelative:=False
Do While rowNumber <= totalRows
Dim currentTask As MSProject.Task
Set currentTask = appProject.ActiveCell.Task
' アクティブセルにタスクが存在する場合のみ処理
If Not currentTask Is Nothing Then
' サマリータスク(グループヘッダー)は処理対象外とする(デザインの一貫性のため)
If Not currentTask.Summary Then
' 色決定のビジネスロジック
Dim targetColor As Long
targetColor = &H0 ' デフォルト:黒 (RGB: 0, 0, 0)
If currentTask.PercentComplete = 100 Then
' 完了:薄グレー (RGB: 128, 128, 128)
targetColor = &H808080
ElseIf currentTask.PercentComplete > 0 And currentTask.PercentComplete < 100 Then
' 進行中:青 (RGB: 0, 102, 204)
targetColor = &HCC6600 ' (リトルエンディアンに注意。VBAではBGR順: &HBBGGRR)
ElseIf currentTask.PercentComplete = 0 And currentTask.Start < Now Then
' 遅延(開始予定を過ぎて未着手):赤 (RGB: 255, 0, 0)
targetColor = &HFF
End If
' 書式の適用 (Font32Exを使用)
' Color引数はBGR形式の16進数、またはRGB関数を使用可能
' 全列(行全体)に適用するため、ApplyToAll:=True とする
appProject.Font32Ex _
Color:=targetColor, _
ApplyToAll:=True
End If
End If
' 次の行へ移動(下矢印キーの挙動をエミュレート)
' 選択が下限に達した場合、自動的にループを抜けるためのハンドリング
On Error Resume Next
appProject.SelectRow Row:=1, RowRelative:=True
If Err.Number <> 0 Then
‘ これ以上下にスクロールできない場合はループを抜ける
Err.Clear
Exit Do
End If
On Error GoTo ErrorHandler
rowNumber = rowNumber + 1
‘ 無限ループ防止用のセーフティネット
If rowNumber > 50000 Then Exit Do
Loop
‘ 5. 元の選択状態へ復元
If originalTaskID > 0 Then
On Error Resume Next
appProject.Find Field:=”ID”, Test:=”equals”, Value:=CStr(originalTaskID)
Err.Clear
On Error GoTo ErrorHandler
End If
CleanExit:
‘ 制御の復元
appProject.ScreenUpdating = True
pj.Calculation = originalCalculation
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “システムエラー”
Resume CleanExit
End Sub
—
4. コードの解説とアーキテクチャの要点
このコードには、ただ「色を変える」だけではない、プロフェッショナルな実装ノウハウが凝縮されています。
① BGR(Blue-Green-Red)カラー指定の罠
VBAの `Font32Ex` メソッドに渡すカラー値は、通常のRGBではなく BGR(リトルエンディアン) で評価されます。
- 赤(RGB: 255, 0, 0) $\rightarrow$ `&H0000FF` (または `&HFF`)
- 青(RGB: 0, 102, 204) $\rightarrow$ `&HCC6600`
- RGB関数(例: `RGB(0, 102, 204)`)を使用しても内部的に変換されるため安全ですが、16進数直書きのほうが実行速度において極めて僅かですが有利です。
② `SelectRow RowRelative:=True` による高速移動
`SelectRow` の `RowRelative:=True` は、現在選択されている位置から相対的に指定行数移動するメソッドです。これを1行ずつ進めることで、フィルターで非表示になっている行を物理的にスキップし、「現在画面に表示されている行」のみを確実かつ高速に処理します。
③ サマリータスクの保護
`If Not currentTask.Summary Then` によって、マイルストーンやWBSの「大項目(サマリータスク)」の色が勝手に変わるのを防いでいます。サマリータスクは上位階層として黒や太字のまま維持することが、ガントチャートの視認性を保つ鉄則です。
—
5. ファイル連携・データベース連携における注意点
もしあなたが、このVBAを「外部システム(SharePoint、Excel、またはSQL Server等)から進捗データを取り込んだ後に実行する」というパイプラインに組み込む場合、以下のライフサイクル管理に注意してください。
1. データ同期直後の実行タイミング
外部データ(進捗率など)をタスクに流し込んだ直後は、MS Projectのスケジュールエンジンが再計算(リンクの解決)を行っている最中です。同期処理の直後に色変更マクロを呼ぶ場合、必ず `pj.Recalculate` を明示的に実行し、計算が完全に完了した状態の値をトリガーにして色判定を行ってください。
2. マルチユーザー環境での競合
MS Project ServerやProject Online環境(エンタープライズ環境)では、ビューのカスタマイズ(フォント色)がチェックイン/チェックアウト時にサーバー側で上書きされることがあります。ローカルの一時的なビュー操作として実行するか、エンタープライズビューに影響を与えないよう、マクロ実行前に「個人用ビュー」が適用されているかを確認するガードコードを入れるのが安全です。
—
まとめ:MS Projectを「ハック」して真の可視化を
MS Project VBAは、Excel VBAの知識がそのまま通用しない「一癖ある」開発領域です。しかし、そのオブジェクトモデルと「データと表現の分離」という思想を正しく理解すれば、これほど強力なプロジェクト統制ツールはありません。
今回紹介したコードは、現場のPM(プロジェクトマネージャー)が「一目で異常に気づく」ための強力な武器になります。ただ仕様書通りに組むだけのプログラマーから脱却し、「ユーザーが思わず唸る、美しく堅牢なガントチャート自動制御」をあなたの現場に提供してください。
