エクセルで工程表を自動作成する方法と、8年でわかった限界

当ページのリンクには広告 (Amazonアソシエイト含む) が含まれています。
ガントチャートをExcelで作る
サクッと結論

関数と条件付き書式だけで、開始日と終了日を入力すればバーが自動で出るところまで作れます。マクロは要りません。

同じ工程表を毎回作り直すなら、テーブル+VBAでボタン1つにできます。

ただし「何%進んだか」「実際にいつ終わったか」は、どちらの方法でも自動にはなりません。ここが最後まで残ります。

私は工場で、設備をいったん止めて行う定期メンテナンス工事の工程表を8年作ってきました。関わる会社も人も多いので、日程が1日ずれるだけで連絡が何本も飛びます。それでも道具はずっとExcelでした。専用ソフトを入れる話にはならず、関係者全員がその場で開けるものが、Excelしかなかったからです。

その工程表を、毎回次のように作っていました。前の年のファイルをコピーして、日付を今年に直して、土日の位置がずれた分だけセルの色を塗り直す。作業を1本足すたびに、3行セットをコピーしてサイズを合わせ直す。私はこれに、毎回半日から丸1日かけていました。

やっていることは工程管理のはずなのに、実際の手の動きはイラストを描く作業でした。バーを細く見せようとすると今度はマウスカーソルが乗らないので、Ctrlとマウスホイールで拡大して、色を塗って、倍率を戻して、文字を書いて、またセルの高さを合わせる。

いまはこの作り直しがありません。独学でExcelの関数とVBAを覚えたからですが、入口は特別なものではなく、この記事に書く数式を1本入れただけでした。そのとおりに組めば、開始日と終了日を打つとバーが出ます。私はここに来るまでに3年かかりました。当時はAIに聞くこともできなかったので、遠回りした部分も含めて全部書きます。

この記事のレベル感

検証環境: Microsoft 365(ビジネス)/ Windows 11 / 確認日 2026年8月9日
※本記事の情報は 2026年8月時点 のものです。最新情報は公式ドキュメントをご確認ください。

Schedikaの画面。左に作業名、右にガントバーが並び、今日の位置に赤い縦線が入っている
サンプルデータを読み込んだところ
PR・自社製品

工程表の作り直しを、手元のPCだけで終わらせる

Excelの工程管理や会議の整理を、手元のPCだけで完結できる時短ツールを作っています。ガントチャートや議事録整理などがあります。クラウドが使えない職場を前提に作りました。

  • インストール不要
  • 外部送信なし
  • CSV・PNGで持ち出せる
時短ツールを見る

無料で試せる版があります。この記事を読むだけでも工程表は作れます。

目次

マクロなしで、バーが自動で出るところまで作る

マクロなしでガントチャートを作成

先に結論を書くと、「工程表の自動作成」と呼ばれるものの大半は、マクロなしで作れます

必要なのは3つだけです。日付の行、土日の色分け、そしてバーの色分け。順番に作ります。

このあと出てくる数式は、次のレイアウトを前提にしています。自分の表に合わせて列番号だけ読み替えてください。

スクロールできます
場所入れるもの
B列作業内容
C列開始日
D列終了日
2行目(E列以降)月。数式で出す
3行目(E列以降)日付そのもの。あとの数式はすべてこの行を見る
4行目(E列以降)曜日。数式で3行目に追従させる
5行目以降作業。1作業につき3行を使う

見出しを3段にしているのには理由があります。列幅を3文字ぶんまで細くしたいので、1つのセルに「9/1(火)」は入りません。月・日・曜を縦に分ければ、1列が細いままでも読めます。現場の工程表がたいていこの形をしているのも同じ理由です。

作業のほうも1行では作りません。1作業につき3行を使います。1行目に作業名と開始日・終了日、2行目にバー、3行目はすきまです。行の高さは上から17・13・5あたりが目安です。

1作業につき3行使用します
1作業につき3行のイメージ

3行に分ける理由は3つあります。バーの行を細くすると線が引き締まって、本数が増えても潰れません。作業名とバーが同じ行にないので、名前が長くてもバーに重なりません。そしてすきまの行があると、作業と作業の切れ目が目で追えます。ここを詰めると、10本を超えたあたりから急に読めなくなります。次の章のVBA版も、同じ3行1セットで描いています。

罫線も先に入れておいてください。カレンダーが右へ長くなると、線の無い表は目で行を追えなくなります。マス目に細い線を敷いたうえで、作業のまとまりごとに1本、少し濃い横線を引くと一気に読めるようになります。月曜の左に薄い縦線を足すと、週の区切りも分かります。なお次の章のVBA版では、この線もボタンを押すたびにマクロが引き直します。

日付の行は「開始日+1」で作る

日付は+1で作りましょう

セルB3に工事の開始日を入れます。そしてC3に、こう書きます。

=B3+1

あとは右へオートフィルするだけです。日付は連番なので、足し算1つで並びます。

ここで大事なのは、日付を手で打たないことです。手で打つと、開始日が1日ずれただけで全部打ち直しになります。E3だけ直せば右が全部ついてくる形にしておくと、あとがまったく違います。

3行目の表示形式は、ユーザー定義で d にします。日にちだけが出るので、列幅3文字でも収まります。

セルの書式設定で「d」とする
セルの書式設定で「d」を設定

曜日の行(4行目)は、真上のセルを見るだけです。B4にこう入れて、書式を aaa にします。

=B3
曜日の箇所に日付を指定する
曜日の箇所に日付を指定
セルの書式設定で「aaa」とする
セルの書式設定で「aaa」を設定

月の行(2行目)は、月が変わる列にだけ「2026年9月」と文字で入れます。3か月の工事でも3回だけなので、手で入れて十分です。

ここは数式にしたくなるところですが、実際にやってみるとうまくいきません。数式が空文字を返すと、Excelはそのセルを「中身がある」と判断して、隣のセルからの文字のはみ出しを止めます。列幅は3文字しかないので、はみ出せないと「202」で切れて読めなくなります。ラベルを置かない列は、数式も入れずに本当に空のままにしてください。

曜日の行は数式のままで問題ありません。3行目の日付を書き換えれば、曜日はついてきます。

土日は条件付き書式とWEEKDAY関数で自動的に塗る

条件付き書式で自動で休日を塗ったExcel

私は最初、土日を手で塗っていました。前年の工程表をコピーすると土日の位置が変わるので、そのたびに塗り直しです。行を1本足すたびにまた塗り直しでした。

これは条件付き書式に置き換えられます。Excelで最初にやめるべき手作業がこれです。

E5から表の右下までを選択して、ホームタブの「条件付き書式」→「新しいルール」→「数式を使用して、書式設定するセルを決定」を選びます。数式欄にこう入れます。

=WEEKDAY(C$3,2)>=6
WEEKDAY関数を指定する
書式ルールの編集

WEEKDAY は日付が何曜日かを数字で返す関数です。第2引数に 2 を指定すると、月曜が1、日曜が7になります。つまり 6以上なら土日です。この対応はMicrosoftサポートの WEEKDAY 関数のページに一覧があります。

E$3$ は行だけを固定する意味です。これを付けないと、下の行に行くほど参照する日付がずれていきます。条件付き書式でいちばん多いつまずきがここです。参照を意味する$ については、絶対参照と相対参照について解説した記事があります。こちらをご覧ください。

同じルールを曜日の行(4行目)にも入れておくと、土日の帯が見出しまで通って読みやすくなります。ただし月の行(2行目)には入れないでください。月のラベルは月初の列にだけ文字を置いて、右隣の空セルへはみ出させて表示しています。その途中に色が入ると、文字の下だけ帯が割り込んだように見えます。日付の行(3行目)も、背景を濃い色にしているなら入れません。土日だけ地の色が変わって、見出しが途切れて見えます。

なお条件付き書式の数式は、等号で始めてTRUEかFALSEを返す形でなければ動きません。またMicrosoftサポートの条件式の解説によると、別のブックへの外部参照は条件付き書式には使えません。祝日リストを別ファイルに置きたくなりますが、同じブックの中に置いてください。

祝日も塗りたい場合は、どこかのシートに祝日の日付を並べて名前を付け(ここでは 祝日 とします)、2つ目のルールとして追加します。

=COUNTIF(祝日,C$3)>0

祝日を除いた営業日で日数を数えたい場合は、WORKDAY関数の使い方NETWORKDAYS関数の解説のほうが向いています。この記事の工程表は「暦日で並べる」前提なので、色分けだけ入れてあります。

バーは「開始日と終了日のあいだなら塗る」だけ

開始日と終了日の間ならセルを塗る

ここが自動作成の本体です。やることは1つで、その列の日付が、その行の開始日と終了日のあいだに入っていたら色を塗る。それだけです。

同じくE5から表の右下を選択して、条件付き書式に次の数式を追加します。

=AND($C5<>"",E$3>=$C5,E$3<=$D5)
書式ルールの編集でセルを塗りつぶす
読み方はこうです。
  • $C5<>"" … 開始日が入っている行だけを対象にする(空の行に色が出るのを防ぐ)
  • E$3>=$C5 … その列の日付が、開始日以降である
  • E$3<=$D5 … その列の日付が、終了日以前である

$C5 は列だけを固定、E$3 は行だけを固定です。この $ の付け方さえ合っていれば、あとは表をどれだけ広げても崩れません。

ここまで作ると、C列とD列に日付を打つだけでバーが出ます。開始日を1日ずらせば、バーも1日ずれます。塗り直しはもう発生しません。

ルールの適用順にだけ注意してください。土日のルールが上にあると、バーが土日で途切れて見えます。「条件付き書式ルールの管理」で、バーのルールを土日より上に置いてください。土日も含めて連続で見せたいならこの順、土日は動かない日として抜いて見せたいなら逆の順です。どちらが正しいということはなく、現場の見方に合わせます。

ここまでの数式は、1作業1行で作った場合のものです。上の3枚の画面も、話を単純にするために1行で撮っています。冒頭の完成形のように1作業3行にするなら、「バーの行だけ塗る」という条件を1つ足します。E5から右下までを選んで、次の数式に差し替えてください。

=AND(MOD(ROW()-5,3)=1,$C4<>"",E$3>=$C4,E$3<=$D4)

足したのは先頭の MOD(ROW()-5,3)=1 だけです。5 は作業が始まる行、3 は1セットの行数。この計算が1になる行が、3行のうちの2行目、つまりバーの行です。参照が $C5 から $C4 に1つ上がっているのは、日付が1行上の作業名の行に入っているからです。範囲はE5から右下までのまま、ルールも2つのままで済みます。作業を足すときは3行ずつ足してください。

なお、条件付き書式を大量に設定したブックは動作が重くなることがあります。Microsoftのサポート記事でも、条件付き書式が多いブックで編集が遅くなる場合があることが案内されています。ただしルール数の上限は公式に数値が示されていませんので、「何個までなら安全」という言い方はできません。私の感覚では、範囲を表の実サイズぴったりに絞っておけば実用上は困りませんでした。

VBAでボタン1つにする(テーブルから工程表を描く)

VBAでガントチャートを記載

ここまでの形で、私は最初の3年をやっていました。次の1年は手塗りとVBAを行ったり来たりして、最後の4年はVBAでした。

正直に書くと、ハイブリッドの1年がいちばんしんどかったです。頭の中に「こうなってほしい」という形はあるのに、当時はAIに聞くこともできなかったので、こうやればいいのかな、いや違うな、を延々とやっていました。いま同じことをやるなら、たぶん数日で組めると思います。

では、なぜ条件付き書式で足りているのにVBAにしたのか。表示する期間を切り替えたかったからです。

条件付き書式のやり方は、カレンダーの列をあらかじめ全部並べておく必要があります。3か月の工事なら90列。ここに「今週だけ見たい」「来月だけ見たい」を足そうとすると、列を隠したりスクロールしたりで結局手が動きます。そこをボタン1つにしたかったというのが動機です。

作業リストは「テーブル」にしておく

作業リストはテーブルにしておく
ガントチャートの表示内容をリストで管理します

VBAにする前に、作業リストをExcelのテーブルにします。範囲を選んで、ホームタブの「テーブルとして書式設定」を選ぶだけです。

テーブルにしておく理由は、行が増えても範囲を書き直さなくていいからです。ふつうのセル範囲だと A2:E50 のように書くことになり、51行目を足した瞬間にコードが拾わなくなります。テーブルなら行を足した分だけ自動で広がります。

Microsoftサポートのテーブルの概要では、フィルタが自動で有効になること、集計列は1つのセルに数式を入れれば列全体に適用されること、テーブル名[列名] という書き方で数式が読みやすくなることが挙げられています。

私が持たせていた列はこれだけです。

スクロールできます
列名中身
作業内容工程の名前
開始日 / 開始時間いつから
終了日 / 終了時間いつまで
備考何か書きたいことがあれば

進捗率の列はありません。これは後で書きますが、最後まで作りませんでした。

日付と時間は別の列にしてください。1つのセルにまとめると、日だけを見たい全体工程のほうで、毎回時刻を切り落とすことになります。分けておけば、全体工程は日の列だけを見て、あとで作る詳細工程が時間の列も見る、という形にできます。

備考は、その作業のバーの真上に出ます。1作業3行にしてあるので、タイトル行のカレンダー側は空いたままです。そこにメモを置くと、右隣の空セルへはみ出して、バーに重ならずに読めます。長い文章を入れると右へ流れていくので、10文字前後までにしておくと収まりがいいです。

あとで出てくるコードは、列を名前で探しています(ListColumns("開始日") という書き方です)。左から何番目かで数えていないので、列を足しても、順番を入れ替えても、マクロは壊れません。使わない列を置いておいても大丈夫です。

テーブルには分かりやすい名前を付けておきます。テーブル内をクリックして「テーブルデザイン」タブの左端で変更できます。名前にはスペースが使えず、ブックの中で重複できない決まりです(構造化参照の公式解説)。

1つだけ決めておくことがあります。このテーブルは、ガントチャートとは別のシートに置いてください。

同じシートに置くと、バーを描く領域とテーブルが場所を取り合います。カレンダーは右へどんどん伸びるので、テーブルをどこに逃がしても、いつか当たります。私は「作業リスト」というシートを作って、そこにはテーブルだけを置いていました。

ボタンを押したら、いったん全部消してから描き直す

ここが設計の分かれ目です。私は上書きではなく、全部消してから描き直す形にしました。

理由は単純で、上書きだと消し忘れが出るからです。作業の期間を短くしたとき、前に塗ったバーの右端が残ります。それを1つずつ判定して消すコードを書くくらいなら、毎回まっさらにしたほうが確実でした。

そして表の左上にドロップダウンを置いて、そこで選んだ日付が表のいちばん左になるようにしました。日付を変えてボタンを押すと、その日を起点に描き直されます。

ドロップダウンの中身は、作業リストのシートの空いているところに日付を並べておき、データタブの「データの入力規則」で種類を「リスト」にして、その範囲を指定するだけです。

候補の日付も手で打つ必要はありません。先頭に1つだけ日付を入れて、その下に =(1つ上のセル)+7 を入れて下へコピーすれば、1週間おきに並びます。日付の行とまったく同じ考え方です。週単位で並べておくと、表示する範囲を1週間ずつずらせます。

1つだけ気をつけてください。入力規則で指定する範囲は、実際に日付が入っている行数ぴったりにします。空のセルまで範囲に入れると、ドロップダウンに空行が並びます。候補を増やすときは、数式を下へコピーしてから範囲も広げてください。なお作業リストのテーブルは下へ伸びるので、候補は右か、別のシートに置いておくとぶつかりません。

コードはこうなります。標準モジュールに貼ってください。VBAをまだ触ったことがない場合は、先にVBAの始め方でエディタの開き方と標準モジュールの作り方を確認しておくと迷いません。

この記事のコードは4つに分かれて出てきますが、中身は1つの標準モジュールです。標準モジュールを1つだけ作って、出てくる順に上から貼り足していけば、最後にそのまま完成します。①この下のコード(設定と全体工程)②詳細工程のコード ③書き出しのコード ④フォルダを選ぶコード、の順です。設定の Private Const は必ずモジュールのいちばん上に置いてください。Subより下に書くとコンパイルエラーになります。

クリックしてすべてのコードを見る
Option Explicit

'==== 設定(自分の表に合わせて、ここだけ変える) ====
Private Const SHEET_NAME    As String = "全体工程"   ' ガントチャートを描くシート
Private Const LIST_SHEET    As String = "作業リスト" ' 作業リストのテーブルがあるシート
Private Const TABLE_NAME    As String = "作業リスト" ' テーブルの名前
Private Const START_CELL    As String = "B2"  ' 表の左端にしたい日付(ドロップダウン)
Private Const MONTH_ROW     As Long = 2       ' 月のラベルを出す行
Private Const HEAD_ROW      As Long = 3       ' 日付を並べる行
Private Const WEEK_ROW      As Long = 4       ' 曜日の行(=E3 の数式が入っている)
Private Const FIRST_ROW     As Long = 5       ' 1件目のタイトル行
Private Const FIRST_COL     As Long = 5       ' E列からカレンダーを描く
Private Const DAY_COUNT     As Long = 60      ' 横に何日ぶん出すか
Private Const ROWS_PER_JOB  As Long = 3       ' タイトル行+バー行+隙間行
Private Const H_TITLE       As Double = 17    ' タイトル行の高さ
Private Const H_BAR         As Double = 13    ' バーの行の高さ(細いほど締まって見える)
Private Const H_GAP         As Double = 5     ' すきまの行の高さ

'---- ここから下は「その日の詳細工程」用 ----
Private Const DAILY_SHEET   As String = "詳細工程" ' 時間単位で描くシート
Private Const DAILY_CELL    As String = "B2"  ' 表示する日付(ドロップダウン)
Private Const HOUR_COUNT    As Long = 24      ' 0時から24時まで並べる
Private Const WORK_START    As Long = 8       ' 日勤の始まり
Private Const WORK_END      As Long = 17      ' 日勤の終わり
Private Const LUNCH_HOUR    As Long = 12      ' 昼休み

Public Sub DrawGantt()
    Dim ws As Worksheet
    Dim lo As ListObject
    Dim baseDate As Date
    Dim i As Long, n As Long
    Dim d As Date
    Dim lastRow As Long
    Dim titleRow As Long, barRow As Long
    Dim sDate As Date, eDate As Date
    Dim sCol As Long, eCol As Long
    Dim memoCol As Long, k As Long
    Dim memo As String

    Set ws = ThisWorkbook.Worksheets(SHEET_NAME)
    Set lo = ThisWorkbook.Worksheets(LIST_SHEET).ListObjects(TABLE_NAME)
    baseDate = ws.Range(START_CELL).Value
    lastRow = FIRST_ROW + lo.ListRows.Count * ROWS_PER_JOB - 1

    ' 備考の列があるかどうかを先に調べておく。無いブックでもエラーにしないため
    memoCol = ColIndex(lo, "備考")

    Application.ScreenUpdating = False

    ' 1) 前回描いた内容を全部消す
    ClearArea ws, DAY_COUNT

    ' 2) 見出しを引き直す(2行目=月・3行目=日。4行目の曜日は数式が追従する)
    ' 月のラベルは必ず「文字」として入れる。日本語のExcelは "2026年9月" を
    ' 日付だと解釈してしまい、列幅が狭いと ### になるため先に表示形式を文字列にする
    ws.Range(ws.Cells(MONTH_ROW, FIRST_COL), _
             ws.Cells(MONTH_ROW, FIRST_COL + DAY_COUNT - 1)).NumberFormat = "@"

    For i = 0 To DAY_COUNT - 1
        d = baseDate + i
        ws.Cells(HEAD_ROW, FIRST_COL + i).Value = d
        ' 月のラベルは左端と月初だけ。隣は空のままにしないと文字がはみ出せない
        If i = 0 Or Day(d) = 1 Then
            ws.Cells(MONTH_ROW, FIRST_COL + i).Value = Format$(d, "yyyy年m月")
        End If
    Next i

    ' 3) 先に土日を塗る(ここから下は塗る順番がそのまま重なる順番になる)
    '    2行目(月のラベル)は塗らない。月名は右隣の空セルへはみ出して表示するので、
    '    途中に色が入ると文字の下だけ帯が入ったように見える
    For i = 0 To DAY_COUNT - 1
        d = baseDate + i
        If Weekday(d, vbMonday) >= 6 Then
            ws.Range(ws.Cells(WEEK_ROW, FIRST_COL + i), _
                     ws.Cells(lastRow, FIRST_COL + i)).Interior.Color = RGB(231, 226, 216)
        End If
    Next i

    ' 4) その上にバーを重ねる
    For n = 1 To lo.ListRows.Count
        titleRow = FIRST_ROW + (n - 1) * ROWS_PER_JOB
        barRow = titleRow + 1

        ' 行の高さもここで揃える。揃えないと3行とも同じ高さのままで、
        ' せっかく3行1セットにしてもバーが太く見えて締まらない
        ws.Rows(titleRow).RowHeight = H_TITLE
        ws.Rows(barRow).RowHeight = H_BAR
        ws.Rows(barRow + 1).RowHeight = H_GAP

        ws.Cells(titleRow, 2).Value = _
            lo.ListColumns("作業内容").DataBodyRange.Cells(n).Value

        sDate = lo.ListColumns("開始日").DataBodyRange.Cells(n).Value
        eDate = lo.ListColumns("終了日").DataBodyRange.Cells(n).Value

        ' 表示している期間から外れている作業は描かない
        If eDate >= baseDate And sDate <= baseDate + DAY_COUNT - 1 Then

            If sDate < baseDate Then sDate = baseDate
            If eDate > baseDate + DAY_COUNT - 1 Then eDate = baseDate + DAY_COUNT - 1

            sCol = FIRST_COL + DateDiff("d", baseDate, sDate)
            eCol = FIRST_COL + DateDiff("d", baseDate, eDate)

            ws.Range(ws.Cells(barRow, sCol), ws.Cells(barRow, eCol)) _
              .Interior.Color = RGB(15, 118, 110)

            ' 備考はバーの真上(タイトル行)に置く。タイトル行のカレンダー側は
            ' 空いているので、右隣の空セルへはみ出してそのまま読める
            If memoCol > 0 Then
                memo = CStr(lo.ListColumns(memoCol).DataBodyRange.Cells(n).Value)
                If Len(memo) > 0 Then
                    With ws.Cells(titleRow, sCol)
                        .Value = memo
                        .HorizontalAlignment = xlLeft
                    End With
                End If
            End If
        End If
    Next n

    ' 5) 最後に罫線を引き直す
    DrawBorders ws, lo.ListRows.Count, baseDate

    Application.ScreenUpdating = True
End Sub

'==== 前回描いた内容を消す(全体工程・詳細工程で共通)====
Private Sub ClearArea(ws As Worksheet, colCount As Long)
    Dim lastRow As Long, lastCol As Long

    ' 消す範囲は「そのシートで何かが入っている最終行」まで。作業名の位置から
    ' 逆算すると、名前を手で消したときに範囲が縮んで、前のバーが残ってしまう
    lastRow = ws.UsedRange.Row + ws.UsedRange.Rows.Count - 1
    If lastRow < FIRST_ROW Then lastRow = FIRST_ROW
    lastCol = FIRST_COL + colCount - 1

    ' 2行目のラベルは値も色も消す
    With ws.Range(ws.Cells(MONTH_ROW, FIRST_COL), ws.Cells(MONTH_ROW, lastCol))
        .ClearContents
        .Interior.ColorIndex = xlNone
    End With

    ' 3行目は「値だけ」消す(見出しの背景色は残したいため)
    ws.Range(ws.Cells(HEAD_ROW, FIRST_COL), ws.Cells(HEAD_ROW, lastCol)).ClearContents

    ws.Range(ws.Cells(WEEK_ROW, FIRST_COL), _
             ws.Cells(WEEK_ROW, lastCol)).Interior.ColorIndex = xlNone

    With ws.Range(ws.Cells(FIRST_ROW, FIRST_COL), ws.Cells(lastRow, lastCol))
        .ClearContents
        .Interior.ColorIndex = xlNone
    End With

    ' 罫線も消す。作業が減ったとき、前回の横線が下に残ってしまうため
    ws.Range(ws.Cells(MONTH_ROW, FIRST_COL), _
             ws.Cells(lastRow, lastCol)).Borders.LineStyle = xlNone
    ws.Range(ws.Cells(WEEK_ROW, 2), ws.Cells(lastRow, 4)).Borders.LineStyle = xlNone
    ws.Range(ws.Cells(FIRST_ROW, 2), ws.Cells(lastRow, 4)).ClearContents

    ' 行の高さも標準に戻す。作業が減ったとき、前回の高さがそのまま残るため
    ws.Rows(FIRST_ROW & ":" & lastRow).UseStandardHeight = True
End Sub

'==== 縦線を1本引く ====
Private Sub VLine(ws As Worksheet, col As Long, lastRow As Long, lineColor As Long)
    With ws.Range(ws.Cells(MONTH_ROW, col), ws.Cells(lastRow, col)).Borders(xlEdgeLeft)
        .LineStyle = xlContinuous
        .Color = lineColor
        .Weight = xlThin
    End With
End Sub

'==== マス目・見出しの下線・作業の区切り線(全体工程・詳細工程で共通)====
Private Sub GridBorders(ws As Worksheet, jobCount As Long, lastCol As Long)
    Dim lastRow As Long, k As Long, n As Long, sepRow As Long
    Dim edges As Variant

    lastRow = FIRST_ROW + jobCount * ROWS_PER_JOB - 1

    ' 1) まず全体に細いマス目を敷く
    '    消す範囲と引く範囲を必ず同じにする。ここを FIRST_ROW から始めると、
    '    見出しの行の罫線を消したまま引き直さないことになる
    edges = Array(xlEdgeLeft, xlEdgeTop, xlEdgeBottom, xlEdgeRight, _
                  xlInsideVertical, xlInsideHorizontal)
    For k = 0 To UBound(edges)
        With ws.Range(ws.Cells(MONTH_ROW, FIRST_COL), _
                      ws.Cells(lastRow, lastCol)).Borders(edges(k))
            .LineStyle = xlContinuous
            .Color = RGB(216, 222, 230)
            .Weight = xlHairline
        End With
    Next k

    ' 2) 見出しの下に1本(B列から右端まで)
    With ws.Range(ws.Cells(WEEK_ROW, 2), _
                  ws.Cells(WEEK_ROW, lastCol)).Borders(xlEdgeBottom)
        .LineStyle = xlContinuous
        .Color = RGB(22, 50, 79)
        .Weight = xlMedium
    End With

    ' 3) 作業のまとまりごとに1本、少し濃い横線
    For n = 1 To jobCount
        sepRow = FIRST_ROW + n * ROWS_PER_JOB - 1
        With ws.Range(ws.Cells(sepRow, 2), _
                      ws.Cells(sepRow, lastCol)).Borders(xlEdgeBottom)
            .LineStyle = xlContinuous
            .Color = RGB(100, 116, 139)
            .Weight = xlThin
        End With
    Next n
End Sub

'==== 全体工程の罫線を引く ====
Private Sub DrawBorders(ws As Worksheet, jobCount As Long, baseDate As Date)
    Dim lastRow As Long, i As Long

    lastRow = FIRST_ROW + jobCount * ROWS_PER_JOB - 1
    GridBorders ws, jobCount, FIRST_COL + DAY_COUNT - 1

    ' 月曜の左に縦線を入れて、週の区切りを見せる
    For i = 0 To DAY_COUNT - 1
        If Weekday(baseDate + i, vbMonday) = 1 Then
            VLine ws, FIRST_COL + i, lastRow, RGB(148, 163, 184)
        End If
    Next i

    VLine ws, FIRST_COL, lastRow, RGB(100, 116, 139)
End Sub

'==== 列の名前から位置を探す。無ければ 0 を返す ====
Private Function ColIndex(lo As ListObject, colName As String) As Long
    Dim k As Long
    ColIndex = 0
    For k = 1 To lo.ListColumns.Count
        If lo.ListColumns(k).Name = colName Then ColIndex = k
    Next k
End Function
つまずきやすいところを分解
  • ListObjects(TABLE_NAME)
  • ListColumns("開始日").DataBodyRange.Cells(n)
    • 「開始日」列の n番目のデータを取る書き方です。見出し行を除いた本体だけを指すのが DataBodyRange です
  • Interior.Color = RGB(15,118,110)
  • DateDiff("d", baseDate, sDate)
    • 起点の日から何日ぶん右にずらすかを出しています。日付の引き算でも動きますが、こう書いたほうが意図が読めます
  • ScreenUpdating = False
    • 描画中の画面のちらつきを止めます。これを入れるかどうかで体感速度がまったく違います
  • NumberFormat = "@"
    • 月のラベルを入れる行を、先に「文字列」にしています。これが無いと、日本語のExcelは 2026年9月 を日付として取り込んでしまい、列幅が狭いセルが # だけの表示になります
  • Borders(xlEdgeBottom)

Cells(行, 列) の書き方でつまずいた場合は、RangeとCellsの使い分けを先に読んでおくと、このコードが全部読めるようになります。

そしてここが実務で効くポイントです。ClearGantt が消しているのは、VBAで塗った色と、書き込んだ値と、引いた罫線だけです。前の章で設定した条件付き書式の土日の色は消えません。

罫線を毎回引き直しているのには理由があります。作業が1件増えれば、区切りの横線を引く行も3行ずれます。手で引いた線は、作業を足した瞬間に表とずれたまま残ります。色と同じで、線も描く側に任せてしまったほうが楽でした。

ここで、前の章で作った土日の条件付き書式をどうするかという話になります。

私はVBAに移行したとき、条件付き書式を全部消しました。

理由は、条件付き書式はVBAで塗った色より優先されるからです。土日の条件付き書式を残したままバーを描くと、せっかく引いたバーが土日のところだけ消えて見えます。どちらが上に出るのかを毎回考えるのが面倒でした。

だから表示を決める場所を1つにしました。先にVBAで土日を一気に塗って、その上からバーを重ねる。コードの3)と4)がその順番です。

見え方はこうなります。

  • 土日に作業が入っていなければ、グレーのまま
  • 土日に作業がかかっていれば、バーの色がそのまま横に抜ける
休日はこのように自動でセルの色塗り。作業時はガントバーの色になります。

マクロなしでいくなら全部条件付き書式、VBAでいくなら全部VBA。混ぜないほうが、あとで悩みません。

その日の詳細工程を、時間で出す

時間のガントチャート

全体工程は日の単位です。ところが現場で朝いちばんに見たいのは、その日1日をどう回すかでした。何時から何が動くのか、どこが重なるのか。これは日の単位の表では出せません。

そこで、日付を選ぶとその日だけを時間で並べるシートを持たせていました。全体工程とは別のシートにしてください。同じシートに混ぜると、列の意味が「日」と「時間」で入れ替わってしまい、どちらも読みにくくなります。

ここで1つ、実際に作ってみないと気づかなかったことがあります。時間の範囲は0時から24時まで必要でした。

日勤の時間帯は8時から17時なので、最初はその範囲だけで作りました。ところが定時より早い時間から動いている作業があるので、それが表に載りません。結局0時から24時まで全部並べて、8時より前と17時より後、それと12時の昼休みをグレーで薄く塗る形に落ち着きました。「ここは人がいない時間ですよ」という意味です。

作業リストに開始時間と終了時間の列を足しておく理由もここです。日をまたぐ作業を、その日の中でどこからどこまでにするかを決めるのに要ります。

スクロールできます
その日が開始終了
作業の初日開始時間から24時まで
途中の日0時から24時まで
最終日0時から終了時間まで
当日で終わる開始時間から終了時間まで

4パターンありますが、コードにすると2行です。

If Int(sVal) = theDate Then sh = Hour(sVal) Else sh = 0
If Int(eVal) = theDate Then eh = Hour(eVal) Else eh = HOUR_COUNT

「その日が初日なら開始時間から、そうでなければ0時から」「その日が最終日なら終了時間まで、そうでなければ24時まで」。これだけで上の表が全部そろいます。Int は日付から時刻を切り落として、日だけにする関数です。

もう1つ、順番に気をつけてください。その日にかかる作業を、塗る前に数えます。本数が決まらないと、グレーの帯をどこまで下ろすかも、罫線をどこまで引くかも決められません。

コードはこうです。ここまでのコードの下に、そのまま貼り足してください。

クリックしてすべてのコードを見る
'==== 作業の開始・終了を「日付+時間」の1つの値にして返す ====
Private Function JobStart(lo As ListObject, n As Long) As Date
    JobStart = Int(lo.ListColumns("開始日").DataBodyRange.Cells(n).Value) + _
               CDbl(lo.ListColumns("開始時間").DataBodyRange.Cells(n).Value)
End Function

Private Function JobEnd(lo As ListObject, n As Long) As Date
    JobEnd = Int(lo.ListColumns("終了日").DataBodyRange.Cells(n).Value) + _
             CDbl(lo.ListColumns("終了時間").DataBodyRange.Cells(n).Value)
End Function

'==== その日の詳細工程を描く ====
Public Sub DrawDaily()
    Dim ws As Worksheet
    Dim lo As ListObject
    Dim theDate As Date
    Dim i As Long, n As Long, k As Long, cnt As Long
    Dim lastRow As Long
    Dim titleRow As Long, barRow As Long
    Dim sVal As Date, eVal As Date
    Dim sh As Long, eh As Long
    Dim idx() As Long
    Dim memoCol As Long
    Dim memo As String

    Set ws = ThisWorkbook.Worksheets(DAILY_SHEET)
    Set lo = ThisWorkbook.Worksheets(LIST_SHEET).ListObjects(TABLE_NAME)

    ' 時間の列が無いと日をまたぐ判定ができないので、ここで止める
    If ColIndex(lo, "開始時間") = 0 Or ColIndex(lo, "終了時間") = 0 Then
        MsgBox "作業リストに「開始時間」「終了時間」の列がありません。", vbExclamation
        Exit Sub
    End If

    theDate = Int(ws.Range(DAILY_CELL).Value)
    memoCol = ColIndex(lo, "備考")

    Application.ScreenUpdating = False

    ClearArea ws, HOUR_COUNT

    ' 1) その日にかかっている作業を先に数える。
    '    行の数が決まらないと、塗る範囲も罫線の範囲も決められない
    ReDim idx(1 To lo.ListRows.Count)
    cnt = 0
    For n = 1 To lo.ListRows.Count
        If Int(JobStart(lo, n)) <= theDate And Int(JobEnd(lo, n)) >= theDate Then
            cnt = cnt + 1
            idx(cnt) = n
        End If
    Next n

    lastRow = FIRST_ROW + cnt * ROWS_PER_JOB - 1
    If lastRow < FIRST_ROW Then lastRow = FIRST_ROW

    ' 2) 時刻の目盛りを並べる。日付は B2 に出ているので、ここには書かない
    '    (同じ日付が2か所に出ると、どちらを直せばいいのか分からなくなる)
    ws.Range(DAILY_CELL).NumberFormatLocal = "yyyy/m/d(aaa)"
    For i = 0 To HOUR_COUNT - 1
        ws.Cells(HEAD_ROW, FIRST_COL + i).Value = i
    Next i

    ' 3) 人がいない時間を先に塗る。8時より前・17時以降・昼休み
    For i = 0 To HOUR_COUNT - 1
        If i < WORK_START Or i >= WORK_END Or i = LUNCH_HOUR Then
            ws.Range(ws.Cells(WEEK_ROW, FIRST_COL + i), _
                     ws.Cells(lastRow, FIRST_COL + i)).Interior.Color = RGB(231, 226, 216)
        End If
    Next i

    ' 4) その上にバーを重ねる
    For k = 1 To cnt
        n = idx(k)
        titleRow = FIRST_ROW + (k - 1) * ROWS_PER_JOB
        barRow = titleRow + 1

        ws.Rows(titleRow).RowHeight = H_TITLE
        ws.Rows(barRow).RowHeight = H_BAR
        ws.Rows(barRow + 1).RowHeight = H_GAP

        sVal = JobStart(lo, n)
        eVal = JobEnd(lo, n)

        ws.Cells(titleRow, 2).Value = _
            lo.ListColumns("作業内容").DataBodyRange.Cells(n).Value

        ' その日の中での開始と終了。前の日から続いていれば0時から、
        ' 次の日へ続くなら24時まで。ここが日をまたぐ作業の扱いになる
        If Int(sVal) = theDate Then sh = Hour(sVal) Else sh = 0
        If Int(eVal) = theDate Then eh = Hour(eVal) Else eh = HOUR_COUNT

        ' 24:00 は時刻として解釈されると日付に化けて #### になる。文字で入れる
        ws.Range(ws.Cells(titleRow, 3), ws.Cells(titleRow, 4)).NumberFormat = "@"
        ws.Cells(titleRow, 3).Value = sh & ":00"
        ws.Cells(titleRow, 4).Value = eh & ":00"

        If eh > sh Then
            ws.Range(ws.Cells(barRow, FIRST_COL + sh), _
                     ws.Cells(barRow, FIRST_COL + eh - 1)).Interior.Color = RGB(15, 118, 110)

            If memoCol > 0 Then
                memo = CStr(lo.ListColumns(memoCol).DataBodyRange.Cells(n).Value)
                If Len(memo) > 0 Then
                    With ws.Cells(titleRow, FIRST_COL + sh)
                        .Value = memo
                        .HorizontalAlignment = xlLeft
                    End With
                End If
            End If
        End If
    Next k

    DrawDailyBorders ws, cnt

    Application.ScreenUpdating = True

    If cnt = 0 Then
        MsgBox Format$(theDate, "m月d日") & " にかかる作業はありません。", vbInformation
    End If
End Sub

'==== 詳細工程の罫線を引く ====
Private Sub DrawDailyBorders(ws As Worksheet, jobCount As Long)
    Dim lastRow As Long

    If jobCount = 0 Then Exit Sub
    lastRow = FIRST_ROW + jobCount * ROWS_PER_JOB - 1
    GridBorders ws, jobCount, FIRST_COL + HOUR_COUNT - 1

    ' 日勤の始まりと終わりに縦線。全体工程の月曜の線と同じ役目
    VLine ws, FIRST_COL + WORK_START, lastRow, RGB(148, 163, 184)
    VLine ws, FIRST_COL + WORK_END, lastRow, RGB(148, 163, 184)
    VLine ws, FIRST_COL, lastRow, RGB(100, 116, 139)
End Sub

日付を選ぶドロップダウンは、全体工程と同じ作り方です。空いているところに日付を並べて、入力規則の「リスト」でその範囲を指定します。並べ終わったら、その列は非表示にしてください。ドロップダウンは元の列を隠したままでも動きます。表の横に日付が延々と並んでいると、それだけで読みにくくなります。

日付そのものは、選ぶセルに1回出れば十分です。同じ日付を見出しにもう一度書かないでください。2か所に出ると、どちらを直せばいいのか分からなくなります。曜日も見たいなら、選ぶセルの表示形式を yyyy/m/d(aaa) にすれば1か所で済みます。

できた工程表をExcelとPDFで書き出す

PDFで出力した結果

ここまでで、全体工程と詳細工程の2枚ができました。出力はExcelとPDFの両方を出せるようにしていました。理由は渡す相手によって欲しい形が違うからです。

  • Excelでほしいという人がいる。自分なりに加工したいからです
  • 私が作った元の版は、変えられたくない。だから確定版はPDFで置きます

社内で共有していたのはPDFのほうでした。この2つを毎回手で作り分けるのが面倒だったので、ボタン1つで両方出す形にしました。

詳細工程のほうを書き出したいときは、SHEET_NAME を DAILY_SHEET に変えるだけです。

クリックしてすべてのコードを見る
Public Sub ExportGantt()
    ' 出力先(初期値。変えたいときはここを直す)
    ' 定数をSubの外に置くならモジュールの先頭にまとめること。
    ' Subより下に書くとコンパイルエラーになるので、ここではSubの中に置いている
    Const EXPORT_DIR As String = "C:\Users\Public\工程表\"

    Dim ws As Worksheet
    Dim baseName As String
    Dim outDir As String

    Set ws = ThisWorkbook.Worksheets(SHEET_NAME)
    outDir = EXPORT_DIR
    ' 末尾の \ を忘れると、フォルダ名がファイル名の頭にくっついて
    ' 1つ上のフォルダに出てしまう。忘れても動くようにここで補う
    If Right$(outDir, 1) <> "\" Then outDir = outDir & "\"
    If Dir(outDir, vbDirectory) = "" Then MkDir outDir
    baseName = Format$(Date, "yyyymmdd") & "_全体工程"

    ' PDFで出す
    ws.ExportAsFixedFormat _
        Type:=xlTypePDF, _
        FileName:=outDir & baseName & ".pdf", _
        Quality:=xlQualityStandard, _
        IgnorePrintAreas:=False, _
        OpenAfterPublish:=False

    ' Excelで出す(このシートだけ別ブックにして保存)
    ws.Copy
    Application.DisplayAlerts = False
    ActiveWorkbook.SaveAs _
        FileName:=outDir & baseName & ".xlsx", _
        FileFormat:=xlOpenXMLWorkbook
    ActiveWorkbook.Close SaveChanges:=False
    Application.DisplayAlerts = True

    MsgBox "書き出しました。" & vbCrLf & outDir, vbInformation
End Sub

PDF出力は ExportAsFixedFormat で、Type:=xlTypePDF を指定します。IgnorePrintAreas:=False にしておくと、シートに設定した印刷範囲がそのまま効きます(Microsoft Learnの ExportAsFixedFormat)。

Excel側の保存で使っている SaveAs は、指定する形式を間違えるとマクロが消えたり、上書き確認のダイアログで処理が止まったりします。そのあたりはWorkbooks.SaveAsの使い方にまとめてあります。

出力先のフォルダは、コードの中に定数として書いていました。変えたくなったらコードを直す、という運用です。乱暴に見えますが、触るのが自分しかいなかったのでこれで足りていました。

出力先のフォルダは、コードの中に定数として書いていました。変えたくなったらコードを直す、という運用です。乱暴に見えますが、触るのが自分しかいなかったのでこれで足りていました。

ただ実際には「今回だけ別の場所に出したい」が起きるので、フォルダを選べる形も付けています。

'==== 保存先をその場で選びたいとき ====
Public Function AskFolder(defaultPath As String) As String
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Title = "書き出し先のフォルダを選んでください"
        .InitialFileName = defaultPath
        If .Show = -1 Then
            AskFolder = .SelectedItems(1) & "\"
        Else
            AskFolder = defaultPath   ' キャンセルなら初期値のまま
        End If
    End With
End Function

自分しか使わないなら定数で十分。誰かに渡すならダイアログを付ける。この線引きだけ先に決めておくと、あとで作り直さずに済みます。

FileDialog は初期フォルダの指定やファイル種類の絞り込みもできます。使い方はVBA FileDialogの使い方にまとめています。

8年使って分かった、自動化できなかったこと

ここからが、この記事でいちばん書きたかったところです。

ボタン1つで工程表が出るようになって、作る時間は確かに消えました。でも8年やって残ったものがあります。

自動化できたのは「描く」ところだけだった

私が作ったVBA版には、進捗率がありません。何パーセント終わったかを書く欄がないし、色も変わりません。

実績を記録する機能もありません。予定どおりに終わったのか、2日延びたのか、それを残す場所を作りませんでした。イナズマ線(進んでいる・遅れているを折れ線で見せるやり方)も入っていません。

できたのは、とりあえず線を引いて「こういう順番でやるんだね」が分かるところまでです。

これは技術的にできなかったわけではありません。作らなかったんです。工事が動いているあいだは翌日の打ち合わせと資料づくりで手一杯で、実績まで手が回らない。実績は未来のために使うものなので、目先は困らない。だから後回しになって、そのまま残らない。

工程に関わっていたのは4人でしたが、実績をきちんと残していたのは1人だけでした。私が残し始めたのは去年からです。8年やって、去年からです。

正直に書きますが、この部分は道具を変えても完全には消えません。自動化できるのは手の動きであって、「終わったあとに入力する」という行為そのものではないからです。ここを「ツールを入れれば解決します」と書いている記事があったら、私は少し疑います。

幅と紙の制約は、最後まで解決しなかった

もう1つ、Excelの構造的な問題です。

工程表を横1枚に収めようとすると、日数が多いほど1列が細くなります。細くなると、バーの中に書いた作業名が読めなくなります。読めるようにすると今度は1枚に収まりません。

対処として無理やりA3にしますが、それ自体が大変です。逆に日数が少なすぎると1列が大きすぎて、スカスカで見栄えが悪い。

期間の長さが、表の読みやすさを決めてしまう。作り手の腕ではどうにもならない部分です。

紙の話も残ります。共有はデータで回していても、紙で持っておきたいという人は必ずいます。そうすると「1枚に収まっていること」が要件になります。横を1枚に収めると縦がスカスカになるので、印刷プレビューを見ながら毎回合わせていました。私は結局、基本はA4に何とか収めて、無理ならA3に諦めて全部A3用に合わせるという運用にしていました。

ちなみにExcelのシートは1,048,576行 × 16,384列まで使えます。容量が足りないわけではありません。足りないのは紙のほうです。

バージョンは増える。増えても困らない置き方にする

これは私も予想が外れたところなので、正直に書きます。

工程は変わるので、直すたびに新しい版が出ます。バージョンはどんどん増えます。ボタン1つで書き出せるようになると、なおさら出しやすくなります。

「自動化したせいで管理が破綻したのでは」と思われそうですが、そうはなりませんでした。理由は単純で、置き場所を1か所に決めていたからです。共有のサーバーに置いて、「最新はここにあります。いちばん新しい番号のものを見てください」で回していました。

版が増えること自体は、実は問題ではありませんでした。問題になるのは手元にコピーが渡ったときです。紙に印刷した瞬間、その紙は更新されません。「これ最新じゃなくないですか」というやりとりは、データではなく紙で起きていました。

ついでに書くと、その日の時間割のほうは、あってもバージョン2か3程度でした。1日分しかないので、そもそも直す回数が少ないんです。版が荒れるのは全体工程のほうだけでした。

だから、対策は「バージョンを増やさない」ではありません。

  • 置き場所を1つに決める(増えてもいいので、探す場所を分散させない)
  • 番号は日付ではなく通し番号にする(同じ日に2回直すことがあるため)
  • 紙に出したものは、その場限りと割り切る

これだけで、実務上は困らなくなりました。

ここまでが、Excelでできることの全部です。私の場合はこの形で4年やって、それから工程表アプリを自作しました。「Excelでこれ以上やっても、幅と紙の問題は消えないな」と思ったのが理由です。

もし同じところで詰まっているなら、まずこの記事の形まで作ってみてください。それで足りるなら、それがいちばん安上がりです。足りなかったときに初めて、Excelの外を考えれば十分だと思います。

PR・自社製品

Schedika(スケディカ)

私がその後に作ったのが、HTMLファイルをChromeやEdgeで開くだけで動くガントチャートアプリです。インストールも通信も要らないので、クラウドが使えない職場を前提にしています。

  • 向いている人:毎週・毎月ダイヤを引き直す人/会議中にその場で工程を組み替えたい人/ソフトのインストールに申請が要る職場の人
  • 向いていない人:工程表を作るのが年に数回の人(この記事の形で足ります)/前の作業がずれた分だけ後ろを自動でずらす機能が要る人(この機能はありません)
  • 無料でできる代替:この記事の条件付き書式とVBAで、作る手間はかなり減らせます。まずそちらを試してからで大丈夫です
Schedika Lite を無料で試す
Schedika Lite の配布ページを開くQRコード
スマホで開く

よくある質問とまとめ

マクロを有効にしても動きません。

ファイルをメールや共有リンクで受け取った場合、Officeが既定でマクロをブロックします。バージョン2206以降の動作で、インターネット由来のファイルには Windows が印(Mark of the Web)を付けるためです。この場合は「セキュリティリスク」のバナーが出て、そもそも有効化ボタンが出ません。

解除するには、ファイルを右クリック→プロパティ→全般タブの下にある「ブロックの解除」にチェックを入れます。詳しくはMicrosoft Learnの「インターネットからのマクロは、Officeで既定でブロックされます」に条件が整理されています。自分で作ったファイルなら、この現象は起きません。

保存したらマクロが消えました。

拡張子が .xlsx になっていませんか。マクロを含むブックは .xlsm で保存する必要があります。「名前を付けて保存」でファイルの種類を「Excel マクロ有効ブック」にしてください。

条件付き書式のバーが、途中で途切れます。

土日のルールがバーのルールより上にある可能性が高いです。「条件付き書式ルールの管理」でバーのルールを上に移動してください。または、数式の $ の付け方(E$3$C5)を見直してください。

マクロなしとVBA、どちらを選べばいいですか。

作る回数で決めるのがおすすめです。

スクロールできます
マクロなし(条件付き書式)VBA
向いている場面工程表を作る回数が年に数回毎週・毎月作り直す
表示期間の切り替え苦手(列を隠す・スクロール)ボタン1つでできる
他の人に渡すそのまま渡せる描いたあと .xlsx で保存すれば、相手にマクロは要らない
覚えること数式と $ の付け方上記+VBAの基礎
進捗率・実績の自動記録できないできない

渡すときの話だけ補足します。VBAで描いたバーは、色と値としてシートに残ります。だから描き終わったものを .xlsx で保存して渡せば、受け取る側にマクロは要りません。マクロが要るのは、作り直す側だけです。

テンプレートは配っていないんですか。

配っていません。この記事の数式とコードをそのまま使えば同じものが作れますし、表のレイアウトは職場ごとに違うので、配ったものを直すほうが手間になると考えているためです。もし「それでもファイルが欲しい」という声が多ければ検討します。

この記事の持ち帰り
  1. コピペで使える条件付き書式の数式 … 土日 =WEEKDAY(E$3,2)>=6 / バー =AND($C5<>"",E$3>=$C5,E$3<=$D5)
  2. テーブルからバーを描くVBAコード … 全部消して描き直す形。設定は先頭の定数だけ変える
  3. 判断のものさし … 年数回ならマクロなし。毎週作り直すならVBA。幅と紙で詰まったらExcelの外

まとめ

  • 「工程表の自動作成」と呼ばれるものの大半は、マクロなしで作れる
    • 開始日と終了日を打てばバーが出るところまでは関数と条件付き書式で足りる
  • 毎回作り直すならVBA。
    • テーブルを作業リストにして、ボタンで全部消して描き直す形が扱いやすい
  • 条件付き書式で足りるものは、コードにしない。
    • 土日は条件付き書式のまま残していい
  • 自動化できるのは「描く」ところまで
    • 進捗率と実績の記録は、どちらの方法でも自動にはならない
  • 幅と紙の制約はExcelの構造の問題
    • 作り手の腕では消えない
  • バージョンは増える。
    • 増やさない努力より、置き場所を1つに決めるほうが効く

私はこの形にたどり着くまでに、手で塗る3年と、試行錯誤の1年を使いました。同じ遠回りをする必要はありません。まずは土日の条件付き書式だけでも入れてみてください。あれが消えるだけで、だいぶ違います。

次にどうするか
スクロールできます
いまの状態次に見るもの
コードが読めなかったVBA(マクロ)入門ガイド。ここからで大丈夫です
コードを書かずに済ませたいSchedika Lite を無料で試す(PR・自社製品)
制限なしで使いたいSchedika Standard の販売ページ(PR・自社製品/買い切り2,980円・2026年8月時点)

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次