zoukankan      html  css  js  c++  java
  • 一款开源且功能强大的C#甘特图控件.NET Winforms Gantt Chart Control

      甘特图在项目管理中非常重要,甘特图的思想比较简单,即以图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间。它直观地表明任务计划在什么时候进行,及实际进展与计划要求的对比。管理者由此可便利地弄清一项任务(项目)还剩下哪些工作要做,并可评估工作进度。甘特图可以显示几个部门、机器或设备的运行和闲置情况。这表示了该系统的有关工作负荷状况,这样可使管理人员了解何种调整是恰当的。

      由于项目需要,在网上找了很久,经过大量的对比和评估,发现一款真正开源且功能强大的C#甘特图控件.NET Winforms Gantt Chart Control(http://ganttchart.codeplex.com/),效果图如下:

     

    该款甘特图控件具有如下特征:

    1、独立的时间单位数据结构规范;
    2、支持单任务,分组任务,先例/依赖的任务,可以对任务进行拆分,并附加资源信息;
    3、打印支持;
    4、可对任务的计划和实际进行对比,以百分比进行进度跟踪;
    5、在直接在甘特图上,对各种鼠标事件进行UI定制;
    6、可以通过继承来修改默认的鼠标命令;
    7、支持关键路径。

    官方演示代码为:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.ComponentModel;
      4 using System.Data;
      5 using System.Drawing;
      6 using System.Linq;
      7 using System.Text;
      8 using System.Windows.Forms;
      9 
     10 namespace Braincase.GanttChart
     11 {
     12     /// <summary>
     13     /// An elaborate example on how the chart control might be used. 
     14     /// Start by collapsing all regions and then read the constructor.
     15     /// Refer to IProjectManager interface for method description.
     16     /// </summary>
     17     public partial class ExampleFull : Form
     18     {
     19         OverlayPainter _mOverlay = new OverlayPainter();
     20 
     21         ProjectManager _mManager = null;
     22 
     23         /// <summary>
     24         /// Example starts here
     25         /// </summary>
     26         public ExampleFull()
     27         {
     28             InitializeComponent();
     29 
     30             // Create a Project and some Tasks
     31             _mManager = new ProjectManager();
     32             var work = new MyTask(_mManager) { Name = "Prepare for Work" };
     33             var wake = new MyTask(_mManager) { Name = "Wake Up" };
     34             var teeth = new MyTask(_mManager) { Name = "Brush Teeth" };
     35             var shower = new MyTask(_mManager) { Name = "Shower" };
     36             var clothes = new MyTask(_mManager) { Name = "Change into New Clothes" };
     37             var hair = new MyTask(_mManager) { Name = "Blow My Hair" };
     38             var pack = new MyTask(_mManager) { Name = "Pack the Suitcase" };
     39 
     40             _mManager.Add(work);
     41             _mManager.Add(wake);
     42             _mManager.Add(teeth);
     43             _mManager.Add(shower);
     44             _mManager.Add(clothes);
     45             _mManager.Add(hair);
     46             _mManager.Add(pack);
     47 
     48             // Create another 1000 tasks for stress testing
     49             Random rand = new Random();
     50             for (int i = 0; i < 1000; i++)
     51             {
     52                 var task = new MyTask(_mManager) { Name = string.Format("New Task {0}", i.ToString()) };
     53                 _mManager.Add(task);
     54                 _mManager.SetStart(task, rand.Next(300));
     55                 _mManager.SetDuration(task, rand.Next(50));
     56             }
     57 
     58             // Set task durations, e.g. using ProjectManager methods 
     59             _mManager.SetDuration(wake, 3);
     60             _mManager.SetDuration(teeth, 5);
     61             _mManager.SetDuration(shower, 7);
     62             _mManager.SetDuration(clothes, 4);
     63             _mManager.SetDuration(hair, 3);
     64             _mManager.SetDuration(pack, 5);
     65 
     66             // demostrate splitting a task
     67             _mManager.Split(pack, new MyTask(_mManager), new MyTask(_mManager), 2);
     68 
     69             // Set task complete status, e.g. using newly created properties
     70             wake.Complete = 0.9f;
     71             teeth.Complete = 0.5f;
     72             shower.Complete = 0.4f;
     73 
     74             // Give the Tasks some organisation, setting group and precedents
     75             _mManager.Group(work, wake);
     76             _mManager.Group(work, teeth);
     77             _mManager.Group(work, shower);
     78             _mManager.Group(work, clothes);
     79             _mManager.Group(work, hair);
     80             _mManager.Group(work, pack);
     81             _mManager.Relate(wake, teeth);
     82             _mManager.Relate(wake, shower);
     83             _mManager.Relate(shower, clothes);
     84             _mManager.Relate(shower, hair);
     85             _mManager.Relate(hair, pack);
     86             _mManager.Relate(clothes, pack);
     87 
     88             // Create and assign Resources.
     89             // MyResource is just custom user class. The API can accept any object as resource.
     90             var jake = new MyResource() { Name = "Jake" };
     91             var peter = new MyResource() { Name = "Peter" };
     92             var john = new MyResource() { Name = "John" };
     93             var lucas = new MyResource() { Name = "Lucas" };
     94             var james = new MyResource() { Name = "James" };
     95             var mary = new MyResource() { Name = "Mary" };
     96             // Add some resources
     97             _mManager.Assign(wake, jake);
     98             _mManager.Assign(wake, peter);
     99             _mManager.Assign(wake, john);
    100             _mManager.Assign(teeth, jake);
    101             _mManager.Assign(teeth, james);
    102             _mManager.Assign(pack, james);
    103             _mManager.Assign(pack, lucas);
    104             _mManager.Assign(shower, mary);
    105             _mManager.Assign(shower, lucas);
    106             _mManager.Assign(shower, john);
    107 
    108             // Initialize the Chart with our ProjectManager and CreateTaskDelegate
    109             _mChart.Init(_mManager);
    110             _mChart.CreateTaskDelegate = delegate() { return new MyTask(_mManager); };
    111 
    112             // Attach event listeners for events we are interested in
    113             _mChart.TaskMouseOver += new EventHandler<TaskMouseEventArgs>(_mChart_TaskMouseOver);
    114             _mChart.TaskMouseOut += new EventHandler<TaskMouseEventArgs>(_mChart_TaskMouseOut);
    115             _mChart.TaskSelected += new EventHandler<TaskMouseEventArgs>(_mChart_TaskSelected);
    116             _mChart.PaintOverlay += _mOverlay.ChartOverlayPainter;
    117             _mChart.AllowTaskDragDrop = true;
    118 
    119             // set some tooltips to show the resources in each task
    120             _mChart.SetToolTip(wake, string.Join(", ", _mManager.ResourcesOf(wake).Select(x => (x as MyResource).Name)));
    121             _mChart.SetToolTip(teeth, string.Join(", ", _mManager.ResourcesOf(teeth).Select(x => (x as MyResource).Name)));
    122             _mChart.SetToolTip(pack, string.Join(", ", _mManager.ResourcesOf(pack).Select(x => (x as MyResource).Name)));
    123             _mChart.SetToolTip(shower, string.Join(", ", _mManager.ResourcesOf(shower).Select(x => (x as MyResource).Name)));
    124 
    125             // Set Time information
    126             _mManager.TimeScale = TimeScale.Day;
    127             var span = DateTime.Today - _mManager.Start;
    128             _mManager.Now = (int)Math.Round(span.TotalDays); // set the "Now" marker at the correct date
    129             _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfWeek; // Set the chart to display days of week in header
    130 
    131             // Init the rest of the UI
    132             _InitExampleUI();            
    133         }
    134 
    135         void _mChart_TaskSelected(object sender, TaskMouseEventArgs e)
    136         {
    137             _mTaskGrid.SelectedObjects = _mChart.SelectedTasks.Select(x => _mManager.IsPart(x) ? _mManager.SplitTaskOf(x) : x).ToArray();
    138             _mResourceGrid.Items.Clear();
    139             _mResourceGrid.Items.AddRange(_mManager.ResourcesOf(e.Task).Select(x => new ListViewItem(((MyResource)x).Name)).ToArray());
    140         }
    141 
    142         void _mChart_TaskMouseOut(object sender, TaskMouseEventArgs e)
    143         {
    144             lblStatus.Text = "";
    145             _mChart.Invalidate();
    146         }
    147 
    148         void _mChart_TaskMouseOver(object sender, TaskMouseEventArgs e)
    149         {
    150             lblStatus.Text = string.Format("{0} to {1}", _mManager.GetDateTime(e.Task.Start).ToLongDateString(), _mManager.GetDateTime(e.Task.End).ToLongDateString());
    151             _mChart.Invalidate();
    152         }
    153 
    154         private void _InitExampleUI()
    155         {
    156             TaskGridView.DataSource = new BindingSource(_mManager.Tasks, null);
    157             mnuFilePrint200.Click += (s, e) => _PrintDocument(2.0f);
    158             mnuFilePrint150.Click += (s, e) => _PrintDocument(1.5f);
    159             mnuFilePrint100.Click += (s, e) => _PrintDocument(1.0f);
    160             mnuFilePrint80.Click += (s, e) => _PrintDocument(0.8f);
    161             mnuFilePrint50.Click += (s, e) => _PrintDocument(0.5f);
    162             mnuFilePrint25.Click += (s, e) => _PrintDocument(0.25f);
    163             mnuFilePrint10.Click += (s, e) => _PrintDocument(0.1f);
    164 
    165             mnuFileImgPrint100.Click += (s, e) => _PrintImage(1.0f);
    166             mnuFileImgPrint50.Click += (s, e) => _PrintImage(0.5f);
    167             mnuFileImgPrint10.Click += (s, e) => _PrintImage(0.1f);            
    168         }
    169 
    170         #region Main Menu
    171 
    172         private void mnuFileSave_Click(object sender, EventArgs e)
    173         {
    174             using (var dialog = new SaveFileDialog())
    175             {
    176                 dialog.InitialDirectory = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
    177                 if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    178                 {
    179                     using (var fs = System.IO.File.OpenWrite(dialog.FileName))
    180                     {
    181                         System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
    182                         bf.Serialize(fs, _mManager);
    183                     }
    184                 }
    185             }
    186         }
    187 
    188         private void mnuFileOpen_Click(object sender, EventArgs e)
    189         {
    190             using (var dialog = new OpenFileDialog())
    191             {
    192                 dialog.InitialDirectory = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
    193                 if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    194                 {
    195                     using (var fs = System.IO.File.OpenRead(dialog.FileName))
    196                     {
    197                         System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
    198                         _mManager = bf.Deserialize(fs) as ProjectManager;
    199                         if (_mManager == null)
    200                         {
    201                             MessageBox.Show("Unable to load ProjectManager. Data structure might have changed from previous verions", "Gantt Chart", MessageBoxButtons.OK, MessageBoxIcon.Error);
    202                         }
    203                         else
    204                         {
    205                             _mChart.Init(_mManager);
    206                             _mChart.Invalidate();
    207                         }
    208                     }
    209                 }
    210             }
    211         }
    212 
    213         private void mnuFileExit_Click(object sender, EventArgs e)
    214         {
    215             this.Close();
    216         }
    217 
    218         private void mnuViewDaysDayOfWeek_Click(object sender, EventArgs e)
    219         {
    220             _mManager.TimeScale = TimeScale.Day;
    221             _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfWeek;
    222             _mChart.Invalidate();
    223         }
    224 
    225         private void mnuFileNew_Click(object sender, EventArgs e)
    226         {
    227             // start a new Project and init the chart with the project
    228             _mManager = new ProjectManager();
    229             _mManager.Add(new Task() { Name = "New Task" });
    230             _mChart.Init(_mManager);
    231             _mChart.Invalidate();
    232         }
    233 
    234         private void mnuHelpAbout_Click(object sender, EventArgs e)
    235         {
    236             if (MessageBox.Show("Please visit http://www.jakesee.com/net-c-winforms-gantt-chart-control/ for more help and details", "Braincase Solutions - Gantt Chart", MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.OK)
    237             {
    238                 System.Diagnostics.Process.Start("http://www.jakesee.com/net-c-winforms-gantt-chart-control/");
    239             }
    240         }
    241 
    242         private void mnuViewRelationships_Click(object sender, EventArgs e)
    243         {
    244             _mChart.ShowRelations = mnuViewRelationships.Checked = !mnuViewRelationships.Checked;
    245             _mChart.Invalidate();
    246         }
    247 
    248         private void mnuViewSlack_Click(object sender, EventArgs e)
    249         {
    250             _mChart.ShowSlack = mnuViewSlack.Checked = !mnuViewSlack.Checked;
    251             _mChart.Invalidate();
    252         }
    253 
    254         private void mnuViewIntructions_Click(object sender, EventArgs e)
    255         {
    256             _mOverlay.PrintMode = !(mnuViewIntructions.Checked = !mnuViewIntructions.Checked);
    257             _mChart.Invalidate();
    258         }
    259 
    260         #region Timescale Views
    261         private void mnuViewDays_Click(object sender, EventArgs e)
    262         {
    263             _mManager.TimeScale = TimeScale.Day;
    264             mnuViewDays.Checked = true;
    265             mnuViewWeek.Checked = false;
    266             _mChart.Invalidate();
    267         }
    268 
    269         private void mnuViewWeek_Click(object sender, EventArgs e)
    270         {
    271             _mManager.TimeScale = TimeScale.Week;
    272             mnuViewDays.Checked = false;
    273             mnuViewWeek.Checked = true;
    274             _mChart.Invalidate();
    275         }
    276 
    277         private void mnuViewDayOfWeek_Click(object sender, EventArgs e)
    278         {
    279             _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfWeek;
    280             mnuViewDayOfWeek.Checked = true;
    281             mnuViewDayOfMonth.Checked = false;
    282             mnuViewWeekOfYear.Checked = false;
    283             _mChart.Invalidate();
    284         }
    285 
    286         private void mnuViewDayOfMonth_Click(object sender, EventArgs e)
    287         {
    288             _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfMonth;
    289             mnuViewDayOfWeek.Checked = false;
    290             mnuViewDayOfMonth.Checked = true;
    291             mnuViewWeekOfYear.Checked = false;
    292             _mChart.Invalidate();
    293         }
    294 
    295         private void mnuViewWeekOfYear_Click(object sender, EventArgs e)
    296         {
    297             _mChart.TimeScaleDisplay = TimeScaleDisplay.WeekOfYear;
    298             mnuViewDayOfWeek.Checked = false;
    299             mnuViewDayOfMonth.Checked = false;
    300             mnuViewWeekOfYear.Checked = true;
    301             _mChart.Invalidate();
    302         }
    303         #endregion Timescale Views
    304 
    305         #endregion Main Menu
    306 
    307         #region Sidebar
    308 
    309         private void _mDateTimePicker_ValueChanged(object sender, EventArgs e)
    310         {
    311             _mManager.Start = _mStartDatePicker.Value;
    312             var span = DateTime.Today - _mManager.Start;
    313             _mManager.Now = (int)Math.Round(span.TotalDays);
    314             if (_mManager.TimeScale == TimeScale.Week) _mManager.Now = (_mManager.Now % 7) * 7;
    315             _mChart.Invalidate();
    316         }
    317 
    318         private void _mPropertyGrid_SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
    319         {
    320             _mChart.Invalidate();
    321         }
    322 
    323         private void _mNowDatePicker_ValueChanged(object sender, EventArgs e)
    324         {
    325             TimeSpan span = _mNowDatePicker.Value - _mStartDatePicker.Value;
    326             _mManager.Now = span.Days + 1;
    327             if (_mManager.TimeScale == TimeScale.Week) _mManager.Now = _mManager.Now / 7 + (_mManager.Now % 7 > 0 ? 1 : 0);
    328             _mChart.Invalidate();
    329         }
    330 
    331         private void _mScrollDatePicker_ValueChanged(object sender, EventArgs e)
    332         {
    333             _mChart.ScrollTo(_mScrollDatePicker.Value);
    334             _mChart.Invalidate();
    335         }
    336 
    337         private void _mTaskGridView_SelectionChanged(object sender, EventArgs e)
    338         {
    339             if (TaskGridView.SelectedRows.Count > 0)
    340             {
    341                 var task = TaskGridView.SelectedRows[0].DataBoundItem as Task;
    342                 _mChart.ScrollTo(task);
    343             }
    344         }
    345 
    346         #endregion Sidebar
    347 
    348         #region Print
    349 
    350         private void _PrintDocument(float scale)
    351         {
    352             using (var dialog = new PrintDialog())
    353             {
    354                 dialog.Document = new System.Drawing.Printing.PrintDocument();
    355                 if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    356                 {
    357                     // set the print mode for the custom overlay painter so that we skip printing instructions
    358                     dialog.Document.BeginPrint += (s, arg) => _mOverlay.PrintMode = true;
    359                     dialog.Document.EndPrint += (s, arg) => _mOverlay.PrintMode = false;
    360 
    361                     // tell chart to print to the document at the specified scale
    362                     _mChart.Print(dialog.Document, scale);
    363                 }
    364             }
    365         }
    366 
    367         private void _PrintImage(float scale)
    368         {
    369             using (var dialog = new SaveFileDialog())
    370             {
    371                 dialog.Filter = "Bitmap (*.bmp) | *.bmp";
    372                 if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    373                 {
    374                     // set the print mode for the custom overlay painter so that we skip printing instructions
    375                     _mOverlay.PrintMode = true;
    376                     // tell chart to print to the document at the specified scale
    377 
    378                     var bitmap = _mChart.Print(scale);
    379                     _mOverlay.PrintMode = false; // restore printing overlays
    380 
    381                     bitmap.Save(dialog.FileName, System.Drawing.Imaging.ImageFormat.Bmp);
    382                 }
    383             }
    384         }
    385 
    386         #endregion Print        
    387 
    388         
    389     }
    390 
    391     #region overlay painter
    392     /// <summary>
    393     /// An example of how to encapsulate a helper painter for painter additional features on Chart
    394     /// </summary>
    395     public class OverlayPainter
    396     {
    397         /// <summary>
    398         /// Hook such a method to the chart paint event listeners
    399         /// </summary>
    400         /// <param name="sender"></param>
    401         /// <param name="e"></param>
    402         public void ChartOverlayPainter(object sender, ChartPaintEventArgs e)
    403         {
    404             // Don't want to print instructions to file
    405             if (this.PrintMode) return;
    406 
    407             var g = e.Graphics;
    408             var chart = e.Chart;
    409 
    410             // Demo: Static billboards begin -----------------------------------
    411             // Demonstrate how to draw static billboards
    412             // "push matrix" -- save our transformation matrix
    413             e.Chart.BeginBillboardMode(e.Graphics);
    414 
    415             // draw mouse command instructions
    416             int margin = 300;
    417             int left = 20;
    418             var color = chart.HeaderFormat.Color;
    419             StringBuilder builder = new StringBuilder();
    420             builder.AppendLine("THIS IS DRAWN BY A CUSTOM OVERLAY PAINTER TO SHOW DEFAULT MOUSE COMMANDS.");
    421             builder.AppendLine("*******************************************************************************************************");
    422             builder.AppendLine("Left Click - Select task and display properties in PropertyGrid");
    423             builder.AppendLine("Left Mouse Drag - Change task starting point");
    424             builder.AppendLine("Right Mouse Drag - Change task duration");
    425             builder.AppendLine("Middle Mouse Drag - Change task complete percentage");
    426             builder.AppendLine("Left Doubleclick - Toggle collaspe on task group");
    427             builder.AppendLine("Right Doubleclick - Split task into task parts");
    428             builder.AppendLine("Left Mouse Dragdrop onto another task - Group drag task under drop task");
    429             builder.AppendLine("Right Mouse Dragdrop onto another task part - Join task parts");
    430             builder.AppendLine("SHIFT + Left Mouse Dragdrop onto another task - Make drop task precedent of drag task");
    431             builder.AppendLine("ALT + Left Dragdrop onto another task - Ungroup drag task from drop task / Remove drop task from drag task precedent list");
    432             builder.AppendLine("SHIFT + Left Mouse Dragdrop - Order tasks");
    433             builder.AppendLine("SHIFT + Middle Click - Create new task");
    434             builder.AppendLine("ALT + Middle Click - Delete task");
    435             builder.AppendLine("Left Doubleclick - Toggle collaspe on task group");
    436             var size = g.MeasureString(builder.ToString(), e.Chart.Font);
    437             var background = new Rectangle(left, chart.Height - margin, (int)size.Width, (int)size.Height);
    438             background.Inflate(10, 10);
    439             g.FillRectangle(new System.Drawing.Drawing2D.LinearGradientBrush(background, Color.LightYellow, Color.Transparent, System.Drawing.Drawing2D.LinearGradientMode.Vertical), background);
    440             g.DrawRectangle(Pens.Brown, background);
    441             g.DrawString(builder.ToString(), chart.Font, color, new PointF(left, chart.Height - margin));
    442 
    443             
    444             // "pop matrix" -- restore the previous matrix
    445             e.Chart.EndBillboardMode(e.Graphics);
    446             // Demo: Static billboards end -----------------------------------
    447         }
    448 
    449         public bool PrintMode { get; set; }
    450     }
    451     #endregion overlay painter
    452 
    453     #region custom task and resource
    454     /// <summary>
    455     /// A custom resource of your own type (optional)
    456     /// </summary>
    457     [Serializable]
    458     public class MyResource
    459     {
    460         public string Name { get; set; }
    461     }
    462     /// <summary>
    463     /// A custom task of your own type deriving from the Task interface (optional)
    464     /// </summary>
    465     [Serializable]
    466     public class MyTask : Task
    467     {
    468         public MyTask(ProjectManager manager)
    469             : base()
    470         {
    471             Manager = manager;
    472         }
    473 
    474         private ProjectManager Manager { get; set; }
    475 
    476         public new int Start { get { return base.Start; } set { Manager.SetStart(this, value); } }
    477         public new int End { get { return base.End; } set { Manager.SetEnd(this, value); } }
    478         public new int Duration { get { return base.Duration; } set { Manager.SetDuration(this, value); } }
    479         public new float Complete { get { return base.Complete; } set { Manager.SetComplete(this, value); } }
    480     }
    481     #endregion custom task and resource
    482 }

    演示效果图为:

  • 相关阅读:
    Python LED
    vmvare虚拟机经验
    Debian系统简要说明
    Android onclick监听事件打开新界面
    在国外搭个人服务器(顺便访问外网)
    生成指定时间内的 随机日起
    生成指定时间内的日期
    Mac 上查找javahome
    java 学习的网站
    Java 线程
  • 原文地址:https://www.cnblogs.com/isaboy/p/ganttcontrol.html
Copyright © 2011-2022 走看看