Project VBAを掌握する極限の知見:MS Projectで「グループ化」を完全自動化し、会議資料の生成コストをゼロにする方法
こんにちは、チーフアーキテクトの私だ。
日々、数千行のWBSと格闘し、リソースの過負荷(オーバーアロケーション)に頭を悩ませているプロジェクトマネージャーや、ツール開発の現場に立つエンジニア諸君。
君たちは、定例会議の直前になって「リソース別にタスクをグループ化したビューを作ってくれ」「いや、やっぱり部署別の工数集計が見たい」といったステークホルダーからの無茶振りに、手動でマウスをカチカチと動かして対応していないか?
「そんな非効率な作業、今すぐコードで自動化しなさい。」
MS ProjectのGUIは、日常的な細かな操作には向いているが、動的なビューの切り替えやレポート作成の自動化においては、手動操作は百害あって一利なしだ。ヒューマンエラーの温床であり、何より時間が惜しい。
今回は、MS Project VBAの隠れた名メソッド `GroupApply` を極限まで使い倒し、リソース別・部署別のビューを瞬時に切り替えて「そのまま会議資料として使える状態」を出力する、堅牢でプロダクション品質のツール設計と実装コードを伝授する。
—
1. なぜ「GroupApply」なのか?(オブジェクトモデルの深層)
MS Projectでグループ化を行う際、初心者が陥りがちな罠が「FilterApply」や「CustomOutlineCode」の場当たり的な乱用だ。これらはデータの構造自体を歪めたり、不要なカスタムフィールドを圧迫したりする。
正解は `Group` オブジェクト と `GroupApply` メソッド の組み合わせだ。
ライフサイクルとパフォーマンスの重みを知る
MS Projectのビュー(View)とテーブル(Table)、そしてグループ(Group)の関係性を正しく理解しなければならない。
アクティブなビューに対してプログラムからグループを適用する場合、Projectは裏側でインデックスの再構築と再計算(Calculation)のコストを支払っている。
ここで、何も考えずに毎回グループ定義を新規作成(Add)するようなコードを書く者がいるが、それは極刑に値する非効率だ。無駄なグループ定義がプロジェクトファイル内に蓄積し、ファイルサイズが肥大化するだけでなく、最悪の場合はオブジェクトの参照リークを引き起こす。
【鉄則】
1. 既存のグループ定義の存在を確認し、なければ作成する。あればそれを再利用する。
2. 画面描画(`ScreenUpdating`)を必ず抑制し、計算コストをコントロールする。
—
2. 堅牢な設計:バグを生む魔物を排除する
実務で動くツールを作るには、以下の「現実の泥臭い問題」をコードで完全にガードしなければならない。
1. 存在しないリソース名やコード指定によるランタイムエラー
2. アクティブビューがグループ化をサポートしていない型(ネットワーク図やカレンダービューなど)だった場合のクラッシュ
3. ファイル破損リスク:マルチユーザー環境(共有プール)での不用意な書き込み
これらをクリアするため、今回提供するコードでは `On Error Resume Next` のような思考停止のエラー逃れは一切使わない。厳格な型チェックとステータス検証を行う。
—
3. 【プロダクションコード】一撃でビューを切り替える自動化モジュール
以下のコードを、MS ProjectのVBE(Visual Basic Editor)の標準モジュールにそのまま貼り付けてほしい。
実務の現場で即座にコピー&ペーストして耐えうる、エラーハンドリング完備の実装だ。
Option Explicit
‘ ==============================================================================
‘ 担当者・アーキテクト特製:MS Project グループ化&ビュー自動化エンジン
‘ ==============================================================================
‘ 定数定義(グループ名)
Private Const GROUP_BY_RESOURCE As String = “【自動】リソース別負荷状況”
Private Const GROUP_BY_DEPT As String = “【自動】部署別コスト集計”
Public Sub ApplyResourceGroupView()
On Error GoTo ErrorHandler
‘ パフォーマンス最適化:画面描画と自動計算の一時停止
AppToggleSettings False
‘ 1. アクティブビューの正当性チェック
If Not IsViewSupportGroup(ActiveProject.ActiveView.Type) Then
Err.Raise 9999, “ViewCheck”, “現在のビュー(” & ActiveProject.ActiveView.Name & “)はグループ化をサポートしていません。「ガントチャート」などに切り替えて実行してください。”
End If
‘ 2. リソース別グループの存在確認と作成・適用
EnsureAndApplyGroup GroupName:=GROUP_BY_RESOURCE, _
FieldType:=pjResource, _
FieldName:=”リソース名”, _
Ascending:=True
‘ 3. ビューの調整(必要に応じてテーブルやフィルターもここで制御可能)
TableApply “タスク入力”
MsgBox “リソース別グループビューへの切り替えが完了しました。”, vbInformation, “自動化ツール”
CleanUp:
AppToggleSettings True
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“内容: ” & Err.Description, vbCritical, “致命的エラー”
Resume CleanUp
End Sub
Public Sub ApplyDepartmentGroupView()
On Error GoTo ErrorHandler
AppToggleSettings False
If Not IsViewSupportGroup(ActiveProject.ActiveView.Type) Then
Err.Raise 9999, “ViewCheck”, “現在のビューはグループ化をサポートしていません。”
End If
‘ 部署別(ここでは例としてユーザー定義の輪郭コード「テキスト1」を想定)
‘ ※実際のプロジェクトのカスタムフィールド定義(Text1等)に合わせて変更してください
EnsureAndApplyGroup GroupName:=GROUP_BY_DEPT, _
FieldType:=pjTask, _
FieldName:=”テキスト1″, _
Ascending:=True
TableApply “コスト”
MsgBox “部署別コスト集計ビューへの切り替えが完了しました。”, vbInformation, “自動化ツール”
CleanUp:
AppToggleSettings True
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “致命的エラー”
Resume CleanUp
End Sub
‘ ——————————————————————————
‘ 内部ロジック:グループの有無を判定し、安全にGroupApplyを実行する
‘ ——————————————————————————
Private Sub EnsureAndApplyGroup(ByVal GroupName As String, ByVal FieldType As PjFieldType, ByVal FieldName As String, ByVal Ascending As Boolean)
Dim grp As Group
Dim groupExists As Boolean
groupExists = False
‘ 既存のグループ定義を走査(TaskGroups または ResourceGroups)
Dim targetGroups As Groups
If FieldType = pjTask Then
Set targetGroups = ActiveProject.TaskGroups
Else
Set targetGroups = ActiveProject.ResourceGroups
End If
On Error Resume Next
Set grp = targetGroups(GroupName)
If Err.Number = 0 Then groupExists = True
On Error GoTo 0
‘ グループが存在しない場合は新規作成
If Not groupExists Then
Set grp = targetGroups.Add(Name:=GroupName)
‘ グループの条件を追加(例: 指定したフィールドでグループ化、昇順)
grp.GroupCriteria.Add FieldName:=FieldName, Ascending:=Ascending
End If
‘ グループの適用
‘ GroupApply Name:=グループ名, [TaskByResource=True/False]
If FieldType = pjResource Then
GroupApply Name:=GroupName
Else
GroupApply Name:=GroupName, TaskByResource:=False
End If
‘ アウトラインの展開レベルを2階層目に設定(会議資料として見やすくする配慮)
OutlineShowAll
OutlineHideSubTasks
‘ 必要に応じてレベル調整
‘ ShowAllTasks
End Sub
‘ ——————————————————————————
‘ サポートビューの判定(ガントチャートやタスクシート等のみ許可)
‘ ——————————————————————————
Private Function IsViewSupportGroup(ByVal viewType As PjViewType) As Boolean
Select Case viewType
Case pjViewGantt, pjViewTaskSheet, pjViewResourceSheet, pjViewResourceUsage, pjViewTaskUsage
IsViewSupportGroup = True
Case Else
IsViewSupportGroup = False
End Select
End Function
‘ ——————————————————————————
‘ パフォーマンス管理(画面描画・計算のON/OFF)
‘ ——————————————————————————
Private Sub AppToggleSettings(ByVal enable As Boolean)
Application.ScreenUpdating = enable
Application.Calculation = IIf(enable, pjAutomatic, pjManual)
End Sub
—
4. 現場で活きるアーキテクトからの助言
データベース連携・共有プール(Resource Pool)利用時の注意点
エンタープライズ環境(Project Server / Project Online / リソースプールファイル共有)において、リソース側のカスタムフィールドやグループ化を操作する場合、ローカルキャッシュとサーバー側の同期ラグに注意しなさい。
特に複数人が同時にアクセスするリソースプールを開いている最中に、マクロから勝手にマスターグループ定義を書き換えようとすると、チェックアウト競合による保存失敗(Save Error)を引き起こす。
もし企業全体のマスターデータを扱うのであれば、グループ定義の動的生成は避け、あらかじめテンプレート(.mpt)側にあらゆるビュー・グループ定義をマスタとして埋め込んでおき、VBA側からは `GroupApply` による「切り替え指示」だけに絞るのが、大規模プロジェクトにおけるベストプラクティスだ。
—
5. 結び:エンジニアの価値は「退屈な手作業の殲滅」にある
プロジェクトマネージャーや管理者が毎朝出社して、マウスでビューをカチカチ切り替え、エクセルにコピペして整形する……そんな前時代的な光景を、君たちの手で終わらせなさい。
今回提供したコードをベースに、リボンメニューやクイックアクセスツールバーに組み込めば、ボタン一つで「会議用エグゼクティブビュー」が秒速で立ち上がる。ステークホルダーは美しい構造化されたデータに感嘆し、君はその裏で自動化された優雅なシステムを静かに微笑みながら見守ればいい。
これこそが、Project VBAを掌握したエンジニアの仕事の流儀だ。さあ、今すぐコードをエディタに叩き込み、現場の景色を変えてこい。
