using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Text;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
namespace ProductionManagement
{
public partial class GanttChart : Form
{
private int _StartMainColumn;
private int _HeaderHeight = 20;
private int _DateColumnWidth = 16;
private DateClass _DateClass = new DateClass();
private Bitmap[] _BitmapArrayDay = new Bitmap[32];
private Bitmap[] _BitmapArrayWeekday = new Bitmap[7];
public GanttChart()
{
InitializeComponent();
Binding();
InitializeTextBox();
CreateDataGridView();
SetupDataGridView();
AttachEvent();
CreateBitmap();
}
private void p(string target) { Debug.Print(target); }
private void AttachEvent()
{
CreateChart.Click += (s, e) => CreateDataGridView();
CreateBar.Click += (s, e) => CreateLabeBar(s, e);
DataGridView.CellPainting += (s, e) => SetupCellPainting(s, e);
DataGridView.Scroll += (s, e) => AllBarLabelTransparent();
DataGridView.SizeChanged += (s, e) => AllBarLabelTransparent();
DataGridView.RowPrePaint += (s, e) => { e.PaintParts &= ~DataGridViewPaintParts.Focus; };
DataGridView.SelectionChanged += (s, e) => DataGridViewHeaderLock();
}
private void CreateLabeBar(object s, EventArgs e)
{
var lb = new MyLabel()
{
Font = DataGridView.Font,
Text = "テスト",
TextAlign = ContentAlignment.MiddleLeft ,
BackColor = Color.Bisque,
Height = DataGridView.RowTemplate.Height - 1,
Width = (_DateColumnWidth * 15) - 1,
rowIndex = 4,
columnIndex = _StartMainColumn
// ID,追番,開始日は初期化時点では未設定
};
this.Controls.Add(lb);
lb.BringToFront();
lb.MouseDoubleClick += (s1, e1) => EditLabelTextOrDelete(s1, e1);
lb.MouseDown += (s2, e2) => LabelMouseDown(s2, e2);
lb.MouseUp += (s3, e3) => LabelMouseUp(s3, e3);
lb.MouseMove += (s4, e4) => LabelMouseMove(s4, e4);
ListMyLabel.Add(lb);
// barLabelもtargetCellもLabelMouseMove()でアクティブなインスタンスが入る
// 明示的に破棄はしていない
barLabel = lb;
targetCell = DataGridView.Rows[4].Cells[_StartMainColumn];
DropBarLabel();
}
private int GetMaxDisplayColumnIndex()
{
for (int c = DataGridView.Columns.Count - 1; c >= 0; c--)
{
if (DataGridView.Rows[DataGridView.FirstDisplayedScrollingRowIndex].Cells[c].Displayed) return c - 1;
}
return DataGridView.Columns.Count - 1;
}
private void InitializeTextBox()
{
DateTime ym = DateTime.Now;
if (ym.Day <= 20) ym = ym.AddMonths(-1);
_DateClass.年月 = ym.ToString("yyyy年MM月");
TargetYm.Text = ym.ToString("yyyy年MM月");
}
private void Binding()
{
TargetYm.DataBindings.Add("Text", _DateClass, "年月");
}
private void CreateBitmap()
{
for (int i = 1; i <= 31; i++)
{
var lb = new Label()
{
Text = i.ToString().PadLeft(2, '0'),
Width = _DateColumnWidth * 3,
Height = _HeaderHeight,
Font = DataGridView.Font,
TextAlign = ContentAlignment.MiddleCenter,
BackColor = Color.AliceBlue
};
var bitmap = new Bitmap(lb.Width, lb.Height);
lb.DrawToBitmap(bitmap, lb.Bounds);
_BitmapArrayDay[i] = bitmap;
}
int j = 0;
foreach (string w in new string[] { "月","火","水","木","金","土","日" })
{
var lb = new Label()
{
Text = w,
Width = _DateColumnWidth * 3,
Height = _HeaderHeight,
Font = DataGridView.Font,
TextAlign = ContentAlignment.MiddleCenter,
BackColor = Color.AliceBlue
};
var bitmap = new Bitmap(lb.Width, lb.Height);
lb.DrawToBitmap(bitmap, lb.Bounds);
_BitmapArrayWeekday[j] = bitmap;
j++;
}
}
private void DrawBorder(object s, DataGridViewCellPaintingEventArgs e)
{
var refer = Convert.ToString(DataGridView.Rows[1].Cells[e.ColumnIndex].Value);
if (refer != "")
{
e.AdvancedBorderStyle.Left = DataGridViewAdvancedCellBorderStyle.OutsetDouble;
// DrawLine()ではrightが上手く表示できない。
// DividerWidthではヘッダー部分まで描画されてしまう。
}
}
private string WeekdayNumber(string target)
{
if (target.Contains("月")) return "0";
if (target.Contains("火")) return "1";
if (target.Contains("水")) return "2";
if (target.Contains("木")) return "3";
if (target.Contains("金")) return "4";
if (target.Contains("土")) return "5";
if (target.Contains("日")) return "6";
return "";
}
private void DrawMergeImage(object s, DataGridViewCellPaintingEventArgs e, bool isWeekday = false)
{
// 画像上で切り取る位置(X,Y)とサイズを指定する。
// ここでは生成済のWidth*3の画像があり、その画像上での位置とサイズを指定する。
var src = new Rectangle(
0,
0,
e.CellBounds.Width,
e.CellBounds.Height
);
// フォーム上で描画する位置を指定する。
var dst = new Rectangle(
e.CellBounds.X,
e.CellBounds.Y,
e.CellBounds.Width,
e.CellBounds.Height - 1
);
var refer = Convert.ToString(DataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value);
var referMinus1 = Convert.ToString(DataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex - 1].Value);
var referMinus2 = Convert.ToString(DataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex - 2].Value);
if (isWeekday)
{
refer = WeekdayNumber(refer);
referMinus1 = WeekdayNumber(referMinus1);
referMinus2 = WeekdayNumber(referMinus2);
}
if (refer != "")
{
if (isWeekday)
{
e.Graphics.DrawImage(_BitmapArrayWeekday[int.Parse(refer)], dst, src, GraphicsUnit.Pixel);
}
else
{
e.Graphics.DrawImage(_BitmapArrayDay[int.Parse(refer)], dst, src, GraphicsUnit.Pixel);
}
e.Graphics.DrawLine(new Pen(DataGridView.GridColor), // left
e.CellBounds.X - 1,
e.CellBounds.Y,
e.CellBounds.X - 1,
e.CellBounds.Y + e.CellBounds.Height
// leftとrightの罫線が重複しているが、leftだけだとクリックしたときに罫線がなくなってしまう
);
e.Graphics.DrawLine(new Pen(DataGridView.GridColor), // top
e.CellBounds.X,
e.CellBounds.Y - 1,
e.CellBounds.X + e.CellBounds.Width,
e.CellBounds.Y - 1
);
e.Graphics.DrawLine(new Pen(DataGridView.GridColor), // bottom
e.CellBounds.X,
e.CellBounds.Y + e.CellBounds.Height - 1,
e.CellBounds.X + e.CellBounds.Width,
e.CellBounds.Y + e.CellBounds.Height - 1
);
e.Handled = true;
}
else if (referMinus1 != "")
{
src.X = e.CellBounds.Width;
if (isWeekday)
{
e.Graphics.DrawImage(_BitmapArrayWeekday[int.Parse(referMinus1)], dst, src, GraphicsUnit.Pixel);
}
else
{
e.Graphics.DrawImage(_BitmapArrayDay[int.Parse(referMinus1)], dst, src, GraphicsUnit.Pixel);
}
e.Graphics.DrawLine(new Pen(DataGridView.GridColor), // top
e.CellBounds.X,
e.CellBounds.Y - 1,
e.CellBounds.X + e.CellBounds.Width,
e.CellBounds.Y - 1
);
e.Graphics.DrawLine(new Pen(DataGridView.GridColor), // bottom
e.CellBounds.X,
e.CellBounds.Y + e.CellBounds.Height - 1,
e.CellBounds.X + e.CellBounds.Width,
e.CellBounds.Y + e.CellBounds.Height - 1
);
e.Handled = true;
}
else if (referMinus2 != "")
{
src.X = e.CellBounds.Width + e.CellBounds.Width;
if (isWeekday)
{
e.Graphics.DrawImage(_BitmapArrayWeekday[int.Parse(referMinus2)], dst, src, GraphicsUnit.Pixel);
}
else
{
e.Graphics.DrawImage(_BitmapArrayDay[int.Parse(referMinus2)], dst, src, GraphicsUnit.Pixel);
}
e.Graphics.DrawLine(new Pen(DataGridView.GridColor), // top
e.CellBounds.X,
e.CellBounds.Y - 1,
e.CellBounds.X + e.CellBounds.Width,
e.CellBounds.Y - 1
);
e.Graphics.DrawLine(new Pen(DataGridView.GridColor), // bottom
e.CellBounds.X,
e.CellBounds.Y + e.CellBounds.Height - 1,
e.CellBounds.X + e.CellBounds.Width,
e.CellBounds.Y + e.CellBounds.Height - 1
);
if (e.RowIndex == 1 || e.RowIndex == 2)
{
e.Graphics.DrawLine(new Pen(DataGridView.GridColor), // right
e.CellBounds.X + e.CellBounds.Width - 1,
e.CellBounds.Y,
e.CellBounds.X + e.CellBounds.Width - 1,
e.CellBounds.Y + e.CellBounds.Height
);
}
e.Handled = true;
}
}
private void SetupCellPainting(object s, DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex == 0)
{
if (e.ColumnIndex < _StartMainColumn)
{
e.AdvancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.None;
}
if (e.ColumnIndex >= _StartMainColumn)
{
e.AdvancedBorderStyle.Left = DataGridViewAdvancedCellBorderStyle.None;
e.AdvancedBorderStyle.Right = DataGridViewAdvancedCellBorderStyle.None;
if (e.ColumnIndex < DataGridView.Columns.Count - 1 &&
Convert.ToString(DataGridView.Rows[0].Cells[e.ColumnIndex + 1].Value) != "")
{
e.AdvancedBorderStyle.Right = DataGridViewAdvancedCellBorderStyle.Single;
}
DrawMergeImage(s, e);
}
}
if (e.RowIndex == 1)
{
if (e.ColumnIndex < _StartMainColumn)
{
e.AdvancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.None;
}
if (e.ColumnIndex >= _StartMainColumn)
{
DrawMergeImage(s, e);
}
}
if (e.RowIndex == 2)
{
if (e.ColumnIndex >= _StartMainColumn)
{
DrawMergeImage(s, e, true);
}
}
if (e.RowIndex > 3)
{
if (e.ColumnIndex >= _StartMainColumn)
{
DrawBorder(s, e);
}
}
}
private void EditLabelTextOrDelete(object s, MouseEventArgs e)
{
var lb = (MyLabel)s;
if ((ModifierKeys & Keys.Control) == Keys.Control)
{
var yesNo = MessageBox.Show("削除しますか?", "", MessageBoxButtons.YesNo);
if (yesNo == DialogResult.Yes) lb.Dispose();
return;
}
var txt = new TextBox()
{
Font = DataGridView.Font,
Multiline = true,
Left = lb.Left,
Top = lb.Top,
Width = lb.Width,
Height = lb.Height,
Text = lb.Text,
};
lb.Visible = false;
Controls.Add(txt);
txt.BringToFront();
txt.Focus();
txt.LostFocus += (s1, e1) =>
{
lb.Text = txt.Text;
lb.Visible = true;
txt.Dispose();
};
}
private bool isBarDrag;
private Point startPoint;
private void LabelMouseDown(object s, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isBarDrag = true;
Cursor.Current = Cursors.Hand;
startPoint.X = e.Location.X;
startPoint.Y = e.Location.Y;
}
if (e.Button == MouseButtons.Right)
{
isBarDrag = true;
Cursor.Current = Cursors.SizeWE;
startPoint.X = e.Location.X;
startPoint.Y = e.Location.Y;
}
}
private void LabelMouseUp(object s, MouseEventArgs e)
{
isBarDrag = false;
Cursor.Current = Cursors.Default;
if (e.Button == MouseButtons.Left)
{
DropBarLabel();
}
if (e.Button == MouseButtons.Right)
{
var diff = barLabel.Width % _DateColumnWidth;
if ( (_DateColumnWidth / 2) <= diff)
{
barLabel.Width = barLabel.Width - diff + _DateColumnWidth - 1;
}
else
{
barLabel.Width = barLabel.Width - diff - 1;
}
int x = barLabel.Location.X + barLabel.Width;
int y = barLabel.Location.Y;
// 座標系変換
x = x - DataGridView.Left;
y = y - DataGridView.Top;
var hitInfo = DataGridView.HitTest(x, y);
SetValueBarLabelEndSide(hitInfo);
}
}
private void SetValueBarLabelEndSide(DataGridView.HitTestInfo hitInfo)
{
if (hitInfo.ColumnIndex == -1) return;
// 追番
barLabel.endDayOrderNumber = Convert.ToString(DataGridView.Rows[3].Cells[hitInfo.ColumnIndex].Value);
// 終了日
var tmp = hitInfo.ColumnIndex;
if (barLabel.endDayOrderNumber == "3") tmp = hitInfo.ColumnIndex - 2;
if (barLabel.endDayOrderNumber == "2") tmp = hitInfo.ColumnIndex - 1;
barLabel.endDay = Convert.ToString(DataGridView.Columns[tmp].Name);
//todo del
barLabel.Text = barLabel.endDay +
" / " + barLabel.endDayOrderNumber;
}
private void SetValueBarLabel(DataGridView.HitTestInfo hitInfo)
{
barLabel.rowIndex = hitInfo.RowIndex;
barLabel.columnIndex = hitInfo.ColumnIndex;
// ID
barLabel.ID = Convert.ToString(DataGridView.Rows[hitInfo.RowIndex].Cells["ID"].Value);
// 追番
barLabel.startDayOrderNumber = Convert.ToString(DataGridView.Rows[3].Cells[hitInfo.ColumnIndex].Value);
// 開始日
var tmp = hitInfo.ColumnIndex;
if (barLabel.startDayOrderNumber == "3") tmp = hitInfo.ColumnIndex - 2;
if (barLabel.startDayOrderNumber == "2") tmp = hitInfo.ColumnIndex - 1;
barLabel.startDay = Convert.ToString(DataGridView.Columns[tmp].Name);
//todo del
barLabel.Text = barLabel.ID +
" / " + barLabel.startDay +
" / " + barLabel.startDayOrderNumber;
}
List<MyLabel> ListMyLabel = new List<MyLabel>();
MyLabel barLabel;
DataGridViewCell targetCell;
private void LabelMouseMove(object s, MouseEventArgs e)
{
if (!isBarDrag) return;
barLabel = (MyLabel)s;
var rightBarLabel = barLabel.Left + barLabel.Width; // BarLabel右端
var rect = DataGridView.GetCellDisplayRectangle(GetMaxDisplayColumnIndex(),
DataGridView.FirstDisplayedScrollingRowIndex, true);
var rightDataGridView = DataGridView.Left + rect.X + rect.Width; // DataGridView右端
if (e.Button == MouseButtons.Left)
{
if (rightBarLabel < rightDataGridView)
{
var x = barLabel.Location.X + e.Location.X - startPoint.X;
var y = barLabel.Location.Y + e.Location.Y - startPoint.Y;
PointingCell(x, y); // Formの座標系
barLabel.Location = new Point(x, y);
}
else if (rightBarLabel >= rightDataGridView)
{
var diff = rightBarLabel - rightDataGridView;
PointingCell(barLabel.Location.X - diff, barLabel.Location.Y);
barLabel.Location = new Point(barLabel.Location.X - diff, barLabel.Location.Y);
isBarDrag = false;
Cursor.Current = Cursors.Default;
DropBarLabel();
}
}
if (e.Button == MouseButtons.Right)
{
if (barLabel.Width >= _DateColumnWidth - 1 && rightBarLabel < rightDataGridView)
{
barLabel.Width += (e.Location.X - startPoint.X);
startPoint.X = e.Location.X;
}
}
}
private void PointingCell(int x, int y)
{
// 座標系の変換
x = x - DataGridView.Left;
y = y - DataGridView.Top;
var hitInfo = DataGridView.HitTest(x, y + DataGridView.RowTemplate.Height / 2); // ここではDgvの座標系
if (hitInfo.ColumnIndex >= _StartMainColumn && hitInfo.RowIndex >= 4)
{
if (targetCell != null &&
targetCell != DataGridView.Rows[hitInfo.RowIndex].Cells[hitInfo.ColumnIndex])
{
targetCell.Style.BackColor = Color.White;
}
// アクティブなインスタンスを入れるのがLabelMouseMove()ではない理由は
// BackColorを戻す処理があるため
targetCell = DataGridView.Rows[hitInfo.RowIndex].Cells[hitInfo.ColumnIndex];
targetCell.Style.BackColor = Color.GreenYellow;
SetValueBarLabel(hitInfo);
}
}
private void DropBarLabel()
{
if (targetCell == null) return;
targetCell.Style.BackColor = Color.White;
var rect = DataGridView.GetCellDisplayRectangle(targetCell.ColumnIndex, targetCell.RowIndex, true);
// 座標系の変換
int x = rect.X + DataGridView.Left;
int y = rect.Y + DataGridView.Top;
BarTransparent(barLabel, x, y);
barLabel.Location = new Point(x, y);
}
private void BarTransparent(MyLabel bar, int x, int y)
{
var leftGap = x - DataGridView.Left;
var rightGap = (DataGridView.Left + DataGridView.Width) - (x + bar.Width);
var topGap = y - DataGridView.Top;
var bottomGap = DataGridView.Bottom - (y + bar.Height);
if (leftGap <= 5 || rightGap <= 5 || topGap <= 5 || bottomGap <= 5)
{
bar.Visible = false;
}
else if (leftGap > 5 && rightGap > 5 && topGap > 5 && bottomGap > 5)
{
bar.Visible = true;
}
}
private void AllBarLabelTransparent()
{
foreach (MyLabel bar in ListMyLabel)
{
var rect = DataGridView.GetCellDisplayRectangle(bar.columnIndex, bar.rowIndex, true);
// 座標系の変換
int x = rect.X + DataGridView.Left;
int y = rect.Y + DataGridView.Top;
BarTransparent(bar, x, y);
bar.Location = new Point(x, y);
}
}
private void DataGridViewHeaderLock()
{
if (DataGridView.Rows.Count >= 2)
{
DataGridView.Rows[0].Selected = false;
DataGridView.Rows[1].Selected = false;
}
}
private void CreateDataGridView()
{
if (TargetYm.Text == "") return;
DataGridView.Rows.Clear();
DataGridView.Columns.Clear();
DateTime ym = DateTime.Parse(TargetYm.Text);
DateTime startDay = new DateTime(ym.Year, ym.Month, 21);
ym = ym.AddMonths(1);
DateTime endDay = new DateTime(ym.Year, ym.Month, 20);
List<DataGridViewColumn> listColumn = new List<DataGridViewColumn>();
string[] mainColumn = new string[] { "ID", "型式", "工番", "数量", "追番" };
foreach (var e in mainColumn)
{
listColumn.Add(new DataGridViewTextBoxColumn
{
Name = e,
HeaderText = ""
});
}
_StartMainColumn = mainColumn.Count();
while (startDay <= endDay) // 列作成
{
for (int i = 1; i <= 3; i++)
{
listColumn.Add(new DataGridViewTextBoxColumn
{
Name = startDay.ToString("yyyy/MM/dd"),
HeaderText = "",
Width = _DateColumnWidth
});
}
startDay = startDay.AddDays(1);
}
DataGridView.Columns.AddRange(listColumn.ToArray());
// ヘッダー追加
for (int i = 0; i < 4; i++)
{
DataGridView.Rows.Add("");
DataGridView.Rows[i].Height = _HeaderHeight;
}
int k = 1;
for (int c = 0; c < listColumn.Count; c++)
{
if (c < _StartMainColumn)
{
DataGridView.Rows[1].Cells[c].Value = listColumn[c].Name;
}
if (c >= _StartMainColumn)
{
DataGridView.Rows[3].Cells[c].Value = k++.ToString(); // 1,2,3
if (k == 4) k = 1;
if (DataGridView.Rows[3].Cells[c].Value.ToString() == "1")
{
DateTime.TryParse(listColumn[c].Name, out DateTime result);
DataGridView.Rows[1].Cells[c].Value = result.ToString("dd"); // 日付
DataGridView.Rows[2].Cells[c].Value = result.ToString("dddd"); // 曜日
if (c == _StartMainColumn || result.ToString("dd") == "01")
{
DataGridView.Rows[0].Cells[c].Value = result.ToString("MM");
}
}
}
}
SetupRowColumn();
DataLoad();
}
private void DataLoad()
{
DataGridView.RowTemplate.Height = 100;
//todo ダミー
DataGridView.Rows.Add("");
DataGridView.Rows.Add("");
DataGridView.Rows.Add("");
DataGridView.Rows.Add("");
DataGridView.Rows.Add("");
DataGridView.Rows.Add("");
DataGridView.Rows.Add("");
DataGridView.Rows.Add("");
DataGridView.Rows.Add("");
DataGridView.Rows.Add("");
DataGridView.Rows.Add("");
DataGridView.Rows.Add("");
int id = 11;
for (int i = 4; i < DataGridView.Rows.Count; i++)
{
DataGridView.Rows[i].Cells["ID"].Value = id++.ToString();
}
}
private void SetupRowColumn()
{
//DataGridView.Columns["ID"].Visible = false;
DataGridView.Rows[0].DefaultCellStyle.BackColor = Color.AliceBlue;
DataGridView.Rows[1].DefaultCellStyle.BackColor = Color.AliceBlue;
DataGridView.Rows[2].DefaultCellStyle.BackColor = Color.AliceBlue;
DataGridView.Rows[3].DefaultCellStyle.BackColor = Color.AliceBlue;
foreach (DataGridViewColumn c in DataGridView.Columns) c.SortMode = DataGridViewColumnSortMode.NotSortable;
}
private void SetupDataGridView()
{
DataGridView.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;
DataGridView.RowHeadersWidth = 4;
DataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
DataGridView.ColumnHeadersHeight = 4;
DataGridView.AllowUserToResizeColumns = false;
DataGridView.ColumnHeadersDefaultCellStyle.WrapMode = DataGridViewTriState.False;
DataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
DataGridView.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
DataGridView.Font = new Font("メイリオ", 9);
DataGridView.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
DataGridView.AllowUserToAddRows = false;
DataGridView.MultiSelect = true;
typeof(DataGridView).
GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).
SetValue(DataGridView, true, null);
}
}
class MyLabel : Label
{
// 保存
public string ID;
public string yearMonth;
public string startDay;
public string startDayOrderNumber;
public string endDay;
public string endDayOrderNumber;
// スクロール
public int rowIndex;
public int columnIndex;
}
class DateClass
{
private string TargetYm;
public object 年月
{
set
{
try
{
var dt = DateTime.Parse(Convert.ToString(value));
TargetYm = dt.ToString("yyyy年MM月");
}
catch
{
TargetYm = "";
}
}
get { return TargetYm; }
}
}
}