0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIに頼り切ってタスクアプリを追加開発する。:WBS、ガントチャート画面ブラッシュアップ②

0
Last updated at Posted at 2026-05-14

前回までの概要

前回まででタスク管理アプリの大枠作成、ブラッシュアップ中となっています。
今回はWBS、ガントチャート画面を再度ブラッシュアップします。

プロンプト

WBS画面のガントチャートに以下要件を追加したい。
 ・月ヘッダ
 ・今日線

回答

WbsForm.Designer.cs 修正版

追加コントロール

private Panel pnlMonthHeader;
InitializeComponent 修正
private void InitializeComponent()
{
    pnlMonthHeader = new Panel();

    dgvWbs = new DataGridView();

    ((System.ComponentModel.ISupportInitialize)
        dgvWbs).BeginInit();

    SuspendLayout();

    // pnlMonthHeader
    pnlMonthHeader.Dock = DockStyle.Top;

    pnlMonthHeader.Height = 35;

    pnlMonthHeader.BackColor = Color.White;

    pnlMonthHeader.Paint += pnlMonthHeader_Paint;

    // dgvWbs
    dgvWbs.Dock = DockStyle.Fill;

    dgvWbs.Location = new Point(0, 35);

    dgvWbs.Name = "dgvWbs";

    dgvWbs.RowTemplate.Height = 28;

    dgvWbs.Scroll += dgvWbs_Scroll;

    dgvWbs.CellPainting += dgvWbs_CellPainting;

    // WbsForm
    AutoScaleDimensions =
        new SizeF(7F, 15F);

    AutoScaleMode =
        AutoScaleMode.Font;

    ClientSize =
        new Size(1400, 700);

    Controls.Add(dgvWbs);

    Controls.Add(pnlMonthHeader);

    Name = "WbsForm";

    Text = "WBS";

    WindowState =
        FormWindowState.Maximized;

    ((System.ComponentModel.ISupportInitialize)
        dgvWbs).EndInit();

    ResumeLayout(false);
}

WbsForm.cs 修正版

フィールド追加

private DateTime _minDate;

private DateTime _maxDate;

private const int DATE_COLUMN_WIDTH = 50;
LoadWbs 修正
private void LoadWbs()
{
    var rows =
        _wbsService.BuildRows(
            _taskService.GetAll());

    if (rows.Count == 0)
    {
        return;
    }

    _minDate =
        rows.Min(x => x.StartDate);

    _maxDate =
        rows.Max(x => x.EndDate);

    int days =
        (_maxDate - _minDate).Days + 1;

    // 日付列追加
    for (int i = 0; i < days; i++)
    {
        DateTime day =
            _minDate.AddDays(i);

        var column =
            new DataGridViewTextBoxColumn();

        column.Name =
            day.ToString("yyyyMMdd");

        column.HeaderText =
            day.ToString("dd");

        column.Width =
            DATE_COLUMN_WIDTH;

        column.SortMode =
            DataGridViewColumnSortMode.NotSortable;

        // 土日色分け
        if (day.DayOfWeek ==
            DayOfWeek.Saturday ||
            day.DayOfWeek ==
            DayOfWeek.Sunday)
        {
            column.DefaultCellStyle.BackColor =
                Color.AliceBlue;
        }

        dgvWbs.Columns.Add(column);
    }

    foreach (var row in rows)
    {
        int index =
            dgvWbs.Rows.Add();

        var gridRow =
            dgvWbs.Rows[index];

        gridRow.Cells[0].Value =
            new string(' ', row.Level * 4)
            + row.TaskName;

        gridRow.Cells[1].Value =
            row.StartDate.ToString("yyyy/MM/dd");

        gridRow.Cells[2].Value =
            row.EndDate.ToString("yyyy/MM/dd");

        for (DateTime d = row.StartDate;
             d <= row.EndDate;
             d = d.AddDays(1))
        {
            int col =
                3 + (d - _minDate).Days;

            gridRow.Cells[col].Style.BackColor =
                Color.DodgerBlue;
        }
    }

    pnlMonthHeader.Invalidate();
}

月ヘッダ描画

重要部分です。

private void pnlMonthHeader_Paint(
    object sender,
    PaintEventArgs e)
{
    Graphics g = e.Graphics;

    g.Clear(Color.White);

    int fixedWidth =
        dgvWbs.Columns[0].Width +
        dgvWbs.Columns[1].Width +
        dgvWbs.Columns[2].Width;

    DateTime current =
        new DateTime(
            _minDate.Year,
            _minDate.Month,
            1);

    while (current <= _maxDate)
    {
        DateTime monthEnd =
            current.AddMonths(1).AddDays(-1);

        if (monthEnd > _maxDate)
        {
            monthEnd = _maxDate;
        }

        int startOffset =
            (current - _minDate).Days;

        if (startOffset < 0)
        {
            startOffset = 0;
        }

        int endOffset =
            (monthEnd - _minDate).Days;

        int x =
            fixedWidth +
            startOffset * DATE_COLUMN_WIDTH;

        int width =
            (endOffset - startOffset + 1)
            * DATE_COLUMN_WIDTH;

        Rectangle rect =
            new Rectangle(
                x,
                0,
                width,
                pnlMonthHeader.Height);

        g.FillRectangle(
            Brushes.LightGray,
            rect);

        g.DrawRectangle(
            Pens.Gray,
            rect);

        StringFormat sf =
            new StringFormat();

        sf.Alignment =
            StringAlignment.Center;

        sf.LineAlignment =
            StringAlignment.Center;

        g.DrawString(
            current.ToString("yyyy/MM"),
            Font,
            Brushes.Black,
            rect,
            sf);

        current =
            current.AddMonths(1);
    }
}

今日線描画

かなり重要。

dgvWbs_CellPainting
private void dgvWbs_CellPainting(
    object sender,
    DataGridViewCellPaintingEventArgs e)
{
    if (e.RowIndex < 0 ||
        e.ColumnIndex < 3)
    {
        return;
    }

    DateTime columnDate =
        _minDate.AddDays(
            e.ColumnIndex - 3);

    if (columnDate.Date ==
        DateTime.Today)
    {
        e.Paint(e.CellBounds,
            DataGridViewPaintParts.All);

        using Pen pen =
            new Pen(Color.Red, 2);

        e.Graphics.DrawLine(
            pen,
            e.CellBounds.Left,
            e.CellBounds.Top,
            e.CellBounds.Left,
            e.CellBounds.Bottom);

        e.Handled = true;
    }
}

スクロール同期

これがないと月ヘッダがズレます。

private void dgvWbs_Scroll(
    object sender,
    ScrollEventArgs e)
{
    pnlMonthHeader.Invalidate();
}

実装、起動確認

実際に実装、動かしてみるとこうなります。

image.png

まとめ

WBSの実用化も一旦完了かと思います。
次回はタスクに持つ項目のブラッシュアップを予定しています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?