在本教程中,将探讨如何从零开始创建一个项目,该项目不仅关注如何旋转图像,而且关注完全用代码实现。正在寻找的是“从头开始”、“自制”的应用程序。准备好接受挑战了吗?
旋转图像的概念很简单。首先,需要找到放置图片角落的位置,然后映射像素,就可以创建出旋转后的图像了。但这听起来像是一项艰巨的工作。幸运的是,有一种更好的方法。在这个问题上,非常重视Graphics
类。不仅因为它能实现想要的功能,还因为它存在于窗体的PaintEventArgs
中,这对于在运行时显示图像、图表和其他东西至关重要。这个“神奇类”将是代码的焦点。但在开始编码之前...
创建一个新的VB项目(注意这个应用程序可以在Visual Studio的Express版本中实现):将其命名为PocketWatchVB
并点击OK。当一个空白窗体出现时,改变FormBorderStyle
为FixedSingle
。这样做是为了防止用户调整窗体大小,从而避免将来可能出现的错误。为了实现平滑的动画效果,将DoubleBuffered
设置为True
。这将确保不会看到任何动画闪烁或质量下降。再次确保样式设置为FixedSingle
。
在进行下一步之前,建议已经准备好了将要用作背景和手表指针的文件。可以从下面下载,自己制作,或者可以使用源代码来检索图像(SRC.zip\Watch\Resources)。如果要自己制作图像,这篇文章是为了256x256的图片尺寸制作的。它们都应该有透明的背景,指针应该比手表略小(但图像尺寸仍然是256x256)。
通过更改Form1
的BackgroundImage
并导入所有四个图像来导入应该保存的四个图像。将所有四个图像导入.resx文件。选择(none)。选择none的目的是导入资源后不需要担心代码中的外部路径,程序更便携,引用资源的代码也更清晰。所以不要设置任何BackgroundImage
,这只是为了导入资源。将窗体的大小设置为370,370。这将使图像位于窗体的正中心。只是为了外观。
如果窗体看起来像这样,做得很好!;)关键是这是一个空白窗体。为了帮助“自制”方面,一切都是在运行时完成的(实际上这种方式更快,更适合叠加图片)。是的,叠加了一个图标。喜欢吗?
为了在开始编码之前了解需要做什么,让使用一个表格。
计时器滴答
重新绘制窗体
绘制背景
找到小时
格式化小时为12小时制
找到分钟
找到所有旋转角度
旋转秒针 - 叠加它
旋转分钟针 - 叠加它
旋转小时针 - 叠加它
很容易看出,大部分代码将用于旋转和叠加时钟的指针,而前半部分的程序则用于达到这一点。
在一切正常工作之前,需要一些声明。这些是项目成功所必需的。
在声明区域导入这些:
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Drawing.Drawing2D
然后声明以下变量:
Dim clockHour As Double
Dim clockmin As Integer
Dim hourAng As Integer
Dim minAng As Integer
Dim secAng As Integer
Dim secBMP As Image = (My.Resources.secondHand)
Dim minBMP As Image = (My.Resources.minuteHand)
Dim hourBMP As Image = (My.Resources.hourHand1)
Dim watchBMP As Image = (My.Resources.PocketWatchProj)
在代码运行之前声明BMPs有助于顺利运行。另一方面,需要在关闭窗体之前释放它们。为此,添加一个Form1_FormClosed()事件处理程序。
Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
secBMP.Dispose()
minBMP.Dispose()
hourBMP.Dispose()
watchBMP.Dispose()
End Sub
好了,开始工作。代码的主要部分将位于Form1_Paint()事件处理程序中。这就是将真正“绘制”窗体的地方。画家将是继承PaintEventArgs的Graphics类,这样就可以“绘制”窗体。也可以绘制控件、面板等,但代码可能需要调整。
e.Graphics.DrawImage(WatchBMP, 0, 0)
首先,让将怀表绘制到窗体的背面。由于这在Form1_paint()事件处理程序中,e指的是PaintEventArgs。这个类允许访问将绘制窗体的Graphics画家。这里只是告诉“画家”在点(0,0)绘制图片(在资源中)。
clockHour = Now.TimeOfDay.Hours
If clockHour > 12 Then
clockHour -= 12
ElseIf clockHour = 0 Then
clockHour = 12
End If
将24小时制转换为12小时制的普通模拟格式,然后根据每个相应的公式计算角度,这并不难理解,只要计算出需要12小时,将360除以12,然后告诉应用程序相应地乘以,等等。
Dim sec As New Matrix()
sec.Translate(1, 1)
sec.RotateAt(secAng, New PointF(170, 170))
e.Graphics.Transform = sec
e.Graphics.DrawImage(secBMP, 0, 0)
sec.Dispose()
这个代码片段创建了一个矩阵,在将更改应用到“画家”之前,可以比普通的Graphics类更成功地操纵矩阵。首先,矩阵被定位,旋转在必要的点以确保时钟的指针不会移出中心,甚至移出屏幕。然后使用e.Graphics.Transform = sec将更改应用到“画家”。在此之后,图像被绘制到窗体上,矩阵被释放以正确地释放资源。
Dim min As New Matrix()
min.Translate(1, 1)
min.RotateAt(minAng, New PointF(170, 170))
e.Graphics.Transform = min
e.Graphics.DrawImage(minBMP, 0, 0)
min.Dispose()
请注意,代码与上一个代码片段相同,只是图像、角度和名称等有所不同。这里不需要太多解释。只是上一个代码片段的重复,这里和那里的变化。
Dim hour As New Matrix()
hour.Translate(0, 0)
hour.RotateAt(hourAng, New PointF(170, 170))
e.Graphics.Transform = hour
e.Graphics.DrawImage(hourBMP, 44, 44)
hour.Dispose()
这里是变化的地方。做同样的事情,除了图像绘制的位置。出于某种原因,如果在正常点绘制图像,它会使它偏离中心,最好的点是(44,44)。
现在工作程序已经完成,需要一种方法来启动它们。添加计时器滴答处理程序来启动这一切。
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Me.Refresh()
End Sub
好的,只是刷新窗体?刷新窗体会使它重新绘制自己。这会调用OnPaint处理程序,它处理所有的职责。那么,让看看这是否有效。运行窗体,时钟应该在一瞬间是空白的,然后看到一张图片。更像是一张自制的图片。=)