前言
我其实很想新建一个分区专门拆解模块来讲解大型项目的,正好,高考倒计时是我第一个成功能够正常运行的第二个大型项目,此模块非Module!
这一次我们拆解——安排表
作为桌面壁纸程序,这个模块会有对应的绘制教程,然而各个模块已经被拆解,因此我会尽量讲的详细,并且把所有重要的知识点放在目录,希望大家可以利用好目录这个东西,看一下目录基本上要解决什么问题只需要点到哪里就行。
目录
1、序列化和反序列化保存和加载配置文件,可以参考VB.net序列化和反序列化的使用方法和实用场景
窗口设计
本次窗口设计简易,紧凑但美观,虽然我们的专业方向是美术与设计类,但是这是后期的问题,我们目前只要搞定后端原理即可,后期可以再优化前端
所有模块
1、序列化和反序列化保存和加载配置文件,可以参考VB.net序列化和反序列化的使用方法和实用场景
2、上下移动安排表和子项
3、绘制多行文字
i、获取文字绘制矩形(范围)
ii、绘制所有文字(重点,范围)
4、经典Windows气球通知
模块解析
2、我们举例ListView这个控件的向上移动的例子
我们的预期是选择一项,可以持续向上移动直到顶部,不能再移动
ar为MyArrangement的一个实例
Private Sub Button18_Click(sender As Object, e As EventArgs) Handles ButUpSub.Click
Dim si = ViewSelectIndex
If ViewSelectIndex > 0 Then
ar.AllList(SelectIndex).SubList.Move(ViewSelectIndex, ViewSelectIndex - 1)
ViewListReload()
ViewSelectIndex = si - 1
End If
End Sub
ar的类结构为(如下图),显然,SubList为一个可移动集合,因此,如果你的基本集合如果只是List的话请直接换成ObservableCollection,他们不会冲突,只是多一个Move方法,仅此而已!
秘密就在于ObservableCollection!
3、绘制文字
我们的预期是:表头在第一行,下边依次是各个子安排,包含可选的(星期,精确分钟,是否通知)
i)、获取文字的矩形
这里需要实例化一个Graphics对象,你可以把bitmap设置为(1,1)大小,节约内存开销,这里不需要bitmap参与,所以我们直接调用MeasureString方法即可
Public Function GetStringSize(s As String, font As Font, sf As StringFormat) As Size
Dim g = Graphics.FromImage(New Bitmap(100, 100))
Dim ScreenSize As New Size(CInt(g.MeasureString(s, font, 9999, sf).Width), CInt(g.MeasureString(s, font, 9999, sf).Height))
Return ScreenSize
End Function
ii)、绘制特定的安排项
预期目标:对单个安排表,绘制子安排,通过循环遍历子安排,获取子安排的输出文字,由于我们现在只支持横向排列单个字符串,所以,如果你需要竖版排列字符串,可以试试
New StringFormat(2)
,然后把部分比如说MaxHeight改成MaxWidth等等。
横板字符串排列代码,通过获取字符串矩形大小获取所有要绘制的字符串的最大宽度,通过所有字符串的高度,获取总高度,完美!
Function DrawArrangement(ar As MyArrangment, index As Integer) As Bitmap
Dim MaxWidth As Integer
Dim MaxHeight As Integer
Dim OriHeight
MaxWidth = GetStringSize(ar.AllList(index).Title, ar.AllList(index).Font, New StringFormat(1)).Width
MaxHeight = GetStringSize(ar.AllList(index).Title, ar.AllList(index).Font, New StringFormat(1)).Height
OriHeight = MaxHeight
For i = 0 To ar.AllList(index).SubList.Count - 1
If MaxWidth < GetStringSize(ar.AllList(index).SubList(i).GetString, ar.AllList(index).Font, New StringFormat(1)).Width Then
MaxWidth = GetStringSize(ar.AllList(index).SubList(i).GetString, ar.AllList(index).Font, New StringFormat(1)).Width
End If
Next
MaxHeight *= ar.AllList(index).SubList.Count + 1
Dim bmp As New Bitmap(MaxWidth, MaxHeight)
Dim g = Graphics.FromImage(bmp)
g.DrawString(ar.AllList(index).Title, ar.AllList(index).Font, New SolidBrush(ar.AllList(index).Color), New Point(0, 0))
For i = 0 To ar.AllList(index).SubList.Count - 1
g.DrawString(ar.AllList(index).SubList(i).GetString, ar.AllList(index).Font, New SolidBrush(ar.AllList(index).Color), New Point(0, OriHeight * (i + 1)))
Next
Return bmp
End Function
输出文字部分
Function GetString() As String
Dim d As String = ""
For Each h In Days
d &= (h & ",")
Next
If d = "-1," Or d.Trim = "" Then
d = ""
Else
d = "星期" & d
End If
Dim c As String
If Format(StartTime, "yyyy-MM-dd HH:mm") <> Format(EndTime, "yyyy-MM-dd HH:mm") Then
c = "(" & Format(StartTime, Arrangement.GetFormat(IsMinite)) & " ~ " & Format(EndTime, Arrangement.GetFormat(IsMinite)) & ")"
End If
Return Name & c & d
End Function
4、Windows气球通知
预期目标:定点执行子安排的启动和结束,可以自己增加执行脚本(本教程不展示)
编写Trigger类,执行LoadTrigger方法时,计算需要等待的时间,开始计时,直到被执行时间到达,执行Post方法,如果单个trigger不需要了,那么就调用UnLoad方法,彻底销毁等待线程
Public Class Trigger
Dim PostInfo As String
Dim t As New Threading.Timer(AddressOf Post)
Sub New()
End Sub
Sub New(d As DateTime, info As String)
SetDate(d, info)
End Sub
Function SetDate(d As DateTime, info As String)
PostInfo = info
Dim now = Date.Now
Dim delta = Math.Ceiling((d - now).TotalSeconds)
If delta < 0 Then
Exit Function
Else
t.Change(CInt(delta) * 1000, 0)
End If
End Function
Sub Post()
Dim n = MainForm.NotifyIcon1
n.BalloonTipTitle = "高考倒计时通知"
n.BalloonTipText = PostInfo
n.ShowBalloonTip(0)
End Sub
Sub UnLoad()
t.DisposeAsync()
End Sub
End Class
什么时候执行?
在每一次重新加载子安排表,重新加载安排,包括但不限于子安排的删除、移动、修改,本地计算机时间更变等,一系列会变的因素要考虑周全!
TodayTrigger是符合当日的子安排项目,以节约内存开销
Sub LoadTrigger()
For Each i In TodayTriggers
i.UnLoad()
Next
TodayTriggers.Clear()
Dim now = Date.Now
Dim week
If now.DayOfWeek = 0 Then
week = 7
Else
week = now.DayOfWeek
End If
For Each a In ar.AllList
For Each s In a.SubList
If s.IsInform Then
If s.IsMinite Then '''精确到分钟,受星期控制
If s.Days.Contains(week) Or s.Days(0) = -1 Then
Dim start = New Date(now.Year, now.Month, now.Day, s.StartTime.Hour, s.StartTime.Minute, 0)
Dim [end] = New Date(now.Year, now.Month, now.Day, s.EndTime.Hour, s.EndTime.Minute, 0)
TodayTriggers.Add(New Trigger(start, "来自安排表:" & a.Title & vbCrLf & " 子安排项:" & s.Name & vbCrLf & "事件活动:启动"))
TodayTriggers.Add(New Trigger([end], "来自安排表:" & a.Title & vbCrLf & " 子安排项:" & s.Name & vbCrLf & "事件活动:结束"))
End If
Else '''不精确到分钟,受日期控制
If s.StartTime.Day = now.Day And s.StartTime.Month = now.Month And s.StartTime.Year = now.Year Then
TodayTriggers.Add(New Trigger(s.StartTime, "来自安排表:" & a.Title & vbCrLf & " 子安排项:" & s.Name & vbCrLf & "事件活动:启动"))
End If
If s.EndTime.Day = now.Day And s.EndTime.Month = now.Month And s.EndTime.Year = now.Year Then
TodayTriggers.Add(New Trigger(s.EndTime, "来自安排表:" & a.Title & vbCrLf & " 子安排项:" & s.Name & vbCrLf & "事件活动:结束"))
End If
End If
End If
Next
Next
End Sub
结语
今后会更多的拆解代码,至于完整源代码,请点开我的主页,下载免费资源研究!!