ガントチャートの「静的」な限界を突破せよ:VBAによる依存関係ベースの動的スタイル制御
MS ProjectのVBAを扱う際、多くのエンジニアが陥る罠がある。それは「オブジェクトモデルをただ叩くだけ」のコードだ。標準機能のガントチャートは、クリティカルパスの可視化には優れているが、複雑なプロジェクトの依存関係(FS, SS, FF, SF)が混在した際、視認性は瞬く間に崩壊する。
本稿では、Project VBAの深い階層を突き、`Task`オブジェクトの依存関係を解析し、ガントチャート上のバー(BarStyle)をプログラム制御で動的に書き換える「動的視覚化エンジン」の構築手法を伝授する。
—
1. 依存関係の深淵:`TaskDependencies` コレクションの真実
VBAから依存関係を制御する場合、`Task.TaskDependencies` プロパティにアクセスするが、ここでのメモリ管理は極めて重要だ。特に数千行規模のWBSを扱う場合、オブジェクトの参照を保持し続けるとガベージコレクションのタイミングを逃し、Project全体のパフォーマンスを著しく低下させる。
極意: 依存関係をループで回す際は、必ず `Nothing` で明示的に解放し、参照カウンタを制御せよ。
2. ガントチャート制御の核心:`BarStyles` のオーバーライド
MS ProjectのUI設定をVBAで直接操作する際、最も強力な武器となるのが `Application.GanttBarStyleAdd` および `GanttBarFormat` オブジェクトだ。しかし、これらは「プロジェクト全体の設定」に影響を与えるため、特定のタスクのみを強調するには、「カスタムフィールドを用いたフィルタリングによる動的スタイル適用」というハックが必要となる。
実装コード:依存関係に基づく動的スタイル判定エンジン
‘ @description 依存関係に基づいてバーの色を動的に変更する最適化ルーチン
‘ @param proj Projectオブジェクト
Public Sub RefreshDependencyStyles(ByRef proj As Project)
Dim tsk As Task
Dim dep As TaskDependency
Dim barColor As Long
‘ メモリリークを防ぐため、画面更新を停止
Application.ScreenUpdating = False
On Error GoTo Cleanup
For Each tsk In proj.Tasks
If Not tsk Is Nothing Then
‘ 依存関係の判定ロジック
For Each dep In tsk.TaskDependencies
‘ FS(Finish-to-Start)であれば標準、それ以外なら赤く強調する例
If dep.Type <> pjFinishToStart Then
‘ タスクのフラグフィールドを更新し、ガントチャートのスタイル定義をトリガーする
tsk.Flag1 = True
Exit For
Else
tsk.Flag1 = False
End If
Next dep
End If
Next tsk
Cleanup:
Application.ScreenUpdating = True
‘ 参照の明示的解放
Set dep = Nothing
Set tsk = Nothing
End Sub
3. パフォーマンスの極限:Windows APIによる描画制御
上記のアプローチでフラグを立てた後、実際にバーの形状を変えるには「ガントチャートの再描画」を強制する必要がある。ここでVBAの標準機能だけを使うと、描画負荷が高い。
シニアレベルの最適化として、`User32.dll` を呼び出し、ウィンドウハンドル(`hWnd`)を通じて再描画メッセージを直接送ることで、UIのちらつきを抑えつつ高速にレンダリングを完了させる。
If VBA7 Then
Private Declare PtrSafe Function InvalidateRect Lib “user32” (ByVal hwnd As LongPtr, ByVal lpRect As LongPtr, ByVal bErase As Long) As Long
Else
Private Declare Function InvalidateRect Lib “user32” (ByVal hwnd As Long, ByVal lpRect As Long, ByVal bErase As Long) As Long
End If
‘ ガントチャートのウィンドウハンドルを取得し、強制再描画をかける
Public Sub ForceGanttRedraw()
Dim hwnd As LongPtr
hwnd = Application.hWndAccessApp ‘ Projectのメインウィンドウ
InvalidateRect hwnd, 0, 1
End Sub
—
4. シニアエンジニアが守るべき「保守性の戒律」
1. オブジェクトの生存期間を最小化せよ: `For Each` ループ内で生成されたオブジェクトは、ループの最後に必ず `Set = Nothing` を実行すること。MS Projectのオブジェクトモデルは、一度スタックに積まれると非常に重い。
2. イベントハンドラの併用: `Project_Change` イベントと組み合わせることで、ユーザーが依存関係を編集した瞬間にスタイルが追従するように設計せよ。ただし、無限ループ(編集→再描画→再編集の検知)には細心の注意が必要だ。
3. レガシー環境への配慮: `PtrSafe` キーワードの使用は必須である。32bit/64bitの混在環境下では、APIの型定義を誤るとProject全体がクラッシュする。
結論
ガントチャートのバーを単なる「線」として捉えるか、あるいは「プロジェクトの動的な状態を表すインジケータ」として捉えるか。そこに、ただのVBAユーザーと、Project VBAを掌握したアーキテクトの境界線がある。
システム管理者は、ツールを動かすのではなく、ツールに「プロジェクトの文脈」を理解させねばならない。このコードをベースに、貴方のプロジェクトに最適な視覚化パイプラインを構築してほしい。
健闘を祈る。
