记得曾经做过一个项目管理软件,前些天看到有些人问起甘特图,想起自己曾经做过一个控件(使用ASP.NET+VB.NET),翻箱倒柜就找了出来,许久以前的东西了,现在看着有点不堪入目了,但想当初也是很费了一番功夫的,为了便于阅读,就把一些枝节的东西去掉了,留下主体的部分,也算个总结吧。
这个控件提供了几个公开的属性,分别是BeginDate(开始日期),EndDate(结束日期),ShowStyle(显示类型,提供三种方式,分别是日视图,周视图,月视图,这个地方用个枚举GttShowStyle传入),Data(传入的数据,是个DataSet,甘特图就是根据里面的数据显示当前的进度),提供了一个公开的方法ReFresh,属性设置完毕后,使用这个方法,就可以显示出甘特图。首先建一个用户控件,空间上拖入个table控件,看html部分应该能够看到<asp:table id="gtttb" runat="server" GridLines="Both"></asp:table>
后台代码部分:
Imports System.Text
Imports System.Math
Imports System.Web.UI.HtmlControls
Imports System.Drawing
Public MustInherit Class gtt
Inherits System.Web.UI.UserControl
'显示类型图,开始日期,结束日期(每个基本格为一天)
Private m_ShowStyle As GttShowStyle
Private m_BeginDate As Date
Private m_EndDate As Date
Private m_data As DataSet
Private tbcell As TableCell ‘单元格
Private m_PreDays As Integer '在日视图中使用,为了从周一开始,可以把起始日期前置,此为前置的天数
Protected WithEvents gtttb As System.Web.UI.WebControls.Table
Public Sub ReFresh()
If m_data.Tables(0).Rows.Count > 0 Then
BindFace()
End If
End Sub
'根据显示类型
Private Sub BindFace()
gtttb.CellPadding = 0
gtttb.CellSpacing = 0
gtttb.BorderColor = Color.FromArgb(153, 153, 153)
gtttb.BackColor = Color.FromArgb(240, 240, 232)
Select Case m_ShowStyle
Case GttShowStyle.ShowDayView ‘日视图
ShowDayView()
Case GttShowStyle.ShowMonthView ‘月视图
ShowMonthView()
Case GttShowStyle.ShowWeekView ‘周视图
ShowWeekView()
End Select
ShowDetail()
End Sub
'显示各种视图的通用部分(包括任务名称,年、月名称)
Private Sub ShowComName()
Dim tbrowY As TableRow = New TableRow()
tbrowY.BackColor = Color.FromArgb(216, 200, 168)
'设置任务名称
Dim tbcell As TableCell = New TableCell()
tbcell.RowSpan = "2"
tbcell.Wrap = False
tbcell.Text = "任 务 名 称"
tbcell.Font.Size = FontUnit.Parse(10)
tbrowY.Cells.Add(tbcell)
Dim Width As Integer '宽度
Dim tmpdate As Date = m_BeginDate '临时数据
m_PreDays = ReturnDayOfWeek(tmpdate) - 1 '返回是本周的第几天
'设置日期头(yyyy-mm)'包括三种格式
Select Case m_ShowStyle
Case GttShowStyle.ShowDayView
'日视图,标头显示,年月日,不过只显示每周开头的日期,下面表示为星期,所以用7作为步进 ok
tmpdate = m_BeginDate.AddDays(-m_PreDays) '从每周一开始
'获得最后一周
Dim tmpenddayofweek As Integer = ReturnDayOfWeek(m_EndDate)
If tmpenddayofweek <> 6 Then
m_EndDate = m_EndDate.AddDays(7 - tmpenddayofweek + 1)
End If
While tmpdate.CompareTo(m_EndDate) < 0
tbcell = New TableCell()
Width = 7
tbcell.Text = tmpdate.Year & "-" & tmpdate.Month & "-" & tmpdate.Day
tbcell.HorizontalAlign = HorizontalAlign.Center
tbcell.ColumnSpan = Width
tbcell.Wrap = False
tbcell.Font.Size = FontUnit.Parse("9")
tbrowY.Cells.Add(tbcell)
tmpdate = tmpdate.AddDays(7)
End While
gtttb.Rows.Add(tbrowY)
Case GttShowStyle.ShowMonthView
'月视图(标头以年为单位) ok
Dim DaysOfYear As Integer
While (tmpdate.Year <= m_EndDate.Year)
tbcell = New TableCell()
If tmpdate.IsLeapYear(tmpdate.Year) Then
DaysOfYear = 366
Else
DaysOfYear = 365
End If
Select Case tmpdate
Case m_BeginDate
'第一个年
Width = DaysOfYear - tmpdate.DayOfYear + 1
Case Else
If tmpdate.Year = m_EndDate.Year Then
'最后一个年
Width = m_EndDate.DayOfYear
Else
'其他的年份
Width = DaysOfYear
End If
End Select
'起始日期与结束日期是同一年的情况
If m_BeginDate.Year = m_EndDate.Year Then
Width = m_EndDate.Subtract(m_BeginDate).Days + 1
End If
tbcell.Text = tmpdate.Year.ToString
tbcell.HorizontalAlign = HorizontalAlign.Center
tbcell.ColumnSpan = Width
tbcell.Wrap = False
tbcell.Font.Size = FontUnit.Parse("9")
tbrowY.Cells.Add(tbcell)
tmpdate = tmpdate.AddYears(1)
End While
gtttb.Rows.Add(tbrowY)
Case GttShowStyle.ShowWeekView
'周视图(标头以月为单位)
Dim DaysOfMonth As Integer
While (tmpdate.CompareTo(m_EndDate) < 0) Or (tmpdate.CompareTo(m_EndDate) > 0 And tmpdate.Subtract(m_EndDate).Days < 7)
tbcell = New TableCell()
DaysOfMonth = tmpdate.DaysInMonth(tmpdate.Year, tmpdate.Month)
If tmpdate.Year = m_BeginDate.Year And tmpdate.Month = m_BeginDate.Month Then
'如果是第一个月
Width = DaysOfMonth - tmpdate.Day + 1
End If
If (tmpdate.Year < m_EndDate.Year) Or (tmpdate.Year = m_EndDate.Year And tmpdate.Month < m_EndDate.Month) Then
'如果是当中的月份
Width = DaysOfMonth
End If
If tmpdate.Year = m_EndDate.Year And tmpdate.Month = m_EndDate.Month Then
'如果是最后的月份
Width = m_EndDate.Day
End If
If m_BeginDate.Year = m_EndDate.Year And m_BeginDate.Month = m_EndDate.Month Then
Width = m_EndDate.Subtract(m_BeginDate).Days + 1
End If
tbcell.Text = tmpdate.Year & "-" & tmpdate.Month
tbcell.HorizontalAlign = HorizontalAlign.Center
tbcell.ColumnSpan = Width
tbcell.Wrap = False
tbcell.Font.Size = FontUnit.Parse("9")
tbrowY.Cells.Add(tbcell)
tmpdate = tmpdate.AddMonths(1)
End While
gtttb.Rows.Add(tbrowY)
End Select
End Sub
'显示日视图
Private Sub ShowDayView()
ShowComName()
'设置天
Dim tmpdate As Date = m_BeginDate.AddDays(-m_PreDays)
Dim tbrowB As TableRow
tbrowB = New TableRow()
tbrowB.BackColor = Color.FromArgb(216, 200, 168)
While tmpdate.CompareTo(m_EndDate) < 0
tbcell = New TableCell()
tbcell.Text = ReturnWeek(tmpdate.DayOfWeek)
tbrowB.Cells.Add(tbcell)
tbcell.Font.Size = FontUnit.Parse("9")
tmpdate = tmpdate.AddDays(1)
End While
gtttb.Rows.Add(tbrowB)
End Sub
Private Function ReturnWeek(ByVal dayofweek As DayOfWeek) As String
Select Case dayofweek
Case dayofweek.Monday
Return "一"
Case dayofweek.Tuesday
Return "二"
Case dayofweek.Wednesday
Return "三"
Case dayofweek.Thursday
Return "四"
Case dayofweek.Friday
Return "五"
Case dayofweek.Saturday
Return "六"
Case dayofweek.Sunday
Return "日"
End Select
End Function
'返回当前日是周几
Private Function ReturnDayOfWeek(ByVal datetmp As Date) As Integer
Select Case datetmp.DayOfWeek
Case DayOfWeek.Monday
Return 1
Case DayOfWeek.Tuesday
Return 2
Case DayOfWeek.Wednesday
Return 3
Case DayOfWeek.Thursday
Return 4
Case DayOfWeek.Friday
Return 5
Case DayOfWeek.Saturday
Return 6
Case DayOfWeek.Sunday
Return 7
End Select
End Function
'显示周视图(还是由天为单位)
Private Sub ShowWeekView()
ShowComName()
'设置周
Dim width As Integer
Dim tmpdate As Date = m_BeginDate
Dim tbrowB As TableRow = New TableRow()
tbrowB.BackColor = Color.FromArgb(216, 200, 168)
Dim WeekCount As Integer = 1
While (tmpdate.CompareTo(m_EndDate) < 0) Or (tmpdate.CompareTo(m_EndDate) > 0 And tmpdate.Subtract(m_EndDate).Days < 7)
tbcell = New TableCell()
tbcell.Text = "第" & WeekCount & "周"
tbcell.ColumnSpan = 7
If (tmpdate.CompareTo(m_EndDate) > 0 And tmpdate.Subtract(m_EndDate).Days < 7) Then
tbcell.ColumnSpan = tmpdate.Subtract(m_EndDate).Days
End If
tbcell.Wrap = False
tbcell.Font.Size = FontUnit.Parse("9")
tbrowB.Cells.Add(tbcell)
tmpdate = tmpdate.AddDays(7)
WeekCount += 1
End While
gtttb.Rows.Add(tbrowB)
End Sub
'显示月视图 ok
Private Sub ShowMonthView()
ShowComName()
'设置月
Dim tmpdate As Date = m_BeginDate
Dim tbrowB As TableRow = New TableRow()
tbrowB.BackColor = Color.FromArgb(216, 200, 168)
Dim DaysOfMonth As Integer
Dim MonthCount As Integer
While (tmpdate.Year < m_EndDate.Year) Or (tmpdate.Year = m_EndDate.Year And tmpdate.Month <= m_EndDate.Month)
'设置宽度
DaysOfMonth = Date.DaysInMonth(tmpdate.Year, tmpdate.Month)
Dim width As Integer
Select Case tmpdate
Case m_BeginDate
'第一个月
width = DaysOfMonth - tmpdate.Day + 1
Case Else
If tmpdate.Year = m_EndDate.Year And tmpdate.Month = m_EndDate.Month Then
'最后一个月
width = m_EndDate.Day
Else
'其他的月份
width = tmpdate.DaysInMonth(tmpdate.Year, tmpdate.Month)
End If
End Select
tbcell = New TableCell()
tbcell.Text = tmpdate.Month
tbcell.ColumnSpan = width
'用最小宽度
tbcell.Wrap = False
tbcell.Font.Size = FontUnit.Parse("9")
tbrowB.Cells.Add(tbcell)
tmpdate = tmpdate.AddMonths(1)
MonthCount += 1
End While
gtttb.Rows.Add(tbrowB)
End Sub
'显示下面的图形
'每个图形部分必须包含三个单元格,中间的单元格背景色作为任务,前面显示的是任务的进度
Private Sub ShowDetail()
Dim drow As DataRow
' = "<img src='../../img/button/depnull.gif' border=0 height=5 width=" & layer * 20 & ">"
For Each drow In m_data.Tables(0).Rows
Dim tbrow As TableRow = New TableRow()
Dim tbname As TableCell = New TableCell()
Dim tbcell1 As TableCell = New TableCell()
Dim tbcell2 As TableCell = New TableCell() '此处显示图形
Dim tbcell3 As TableCell = New TableCell()
Dim firstwidth As Integer
Dim midwidth As Integer
Dim endwidth As Integer
If ShowStyle = GttShowStyle.ShowDayView Then
firstwidth = CType(drow("bdate"), Date).Subtract(CType(m_BeginDate, Date).AddDays(-m_PreDays)).Days
midwidth = CType(drow("edate"), Date).Subtract(CType(drow("bdate"), Date)).Days + 1
endwidth = CType(m_EndDate, Date).Subtract(CType(drow("edate"), Date)).Days + 1
Else
firstwidth = CType(drow("bdate"), Date).Subtract(CType(m_BeginDate, Date)).Days + 1
midwidth = CType(drow("edate"), Date).Subtract(CType(drow("bdate"), Date)).Days + 1
endwidth = CType(m_EndDate, Date).Subtract(CType(drow("edate"), Date)).Days + 1
End If
If drow("layer") < 3 Then
tbname.Text = "<img src='../../img/button/depnull.gif' border=0 height=3 width=" & (drow("layer") + 1) * 20 & ">" & "<img src='../../img/number" & drow("layer") + 2 & ".gif' border=0 height=12 >" & drow("name")
Else
tbname.Text = "<img src='../../img/button/depnull.gif' border=0 height=3 width=" & (drow("layer") + 1) * 20 & ">" & drow("name")
End If
tbname.Wrap = False
tbname.Font.Size = FontUnit.Parse("9")
tbcell1.ColumnSpan = firstwidth
tbcell2.ColumnSpan = midwidth
'显示图形
tbcell2.VerticalAlign = VerticalAlign.Middle
tbcell2.BackColor = Color.SteelBlue
Dim btn As New Button()
Dim width As String = (drow("taskpercent") * 100).ToString & "%"
btn.Width = Unit.Parse(width)
'根据任务的执行情况,设定背景色
Select Case drow("state")
Case True '已完成
btn.BackColor = Color.Green
Case False '进行中
btn.BackColor = Color.GreenYellow
End Select
btn.Height = Unit.Parse(6)
btn.Enabled = False
'根据是否超时,超支,确定边框的颜色
If drow("cost") > drow("plancost") Or (CType(drow("edate"), Date).CompareTo(Date.Now) < 0 And Not drow("state")) Then
tbcell2.BorderWidth = Unit.Parse(2)
tbcell2.BorderColor = Color.Red
End If
tbcell2.Controls.Add(btn)
tbcell3.ColumnSpan = endwidth
tbrow.Cells.Add(tbname)
tbrow.Cells.Add(tbcell1)
tbrow.Cells.Add(tbcell2)
tbrow.Cells.Add(tbcell3)
gtttb.Rows.Add(tbrow)
Next
End Sub
'设置此控件的属性
'开始日期
Public Property BeginDate() As Date
Get
Return m_BeginDate
End Get
Set(ByVal Value As Date)
m_BeginDate = Value
End Set
End Property
'结束日期
Public Property EndDate() As Date
Get
Return m_EndDate
End Get
Set(ByVal Value As Date)
m_EndDate = Value
End Set
End Property
'显示哪种视图
Public Property ShowStyle() As GttShowStyle
Get
Return m_ShowStyle
End Get
Set(ByVal Value As GttShowStyle)
m_ShowStyle = Value
End Set
End Property
'在此图中欲显示的数据(此处应固定格式,也许应该从某个地方继承)
Public Property Data() As DataSet
Get
Return m_data
End Get
Set(ByVal Value As DataSet)
m_data = Value
End Set
End Property
'确定显示的类型(包括日视图,周视图,月视图)
Public Enum GttShowStyle
ShowDayView = -1
ShowWeekView = 0
ShowMonthView = 1
End Enum
End Class
以上代码构成了甘特图的主体部分,现在重新检查代码,感觉问题还是不少的,不过作为前进中的纪念,还是基本按照原样记录下来。