65.9K
CodeProject 正在变化。 阅读更多。
Home

怀表 - VB

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.96/5 (7投票s)

2010年3月14日

CPOL

7分钟阅读

viewsIcon

46481

downloadIcon

1808

从零开始制作一个怀表

注意:这些文件的名称为

  • RunIt3.zip
  • SRC3.zip
Final.jpg

挑战

挑战在于从头开始创建一个项目,该项目既关注如何旋转图像,也关注如何完全用代码实现。我们寻找的是“从头开始”、“自制”的应用程序。你有这个能力吗?

概念

旋转图像的概念很简单。首先,找到一个地方放置图片的角,然后映射像素,一张旋转后的图片就完成了。

但等等,这听起来工作量很大。

是的,确实如此。不仅仅是程序员,对程序本身来说也是如此。这需要巨大的资源和时间(以计算机的尺度来衡量)。

一定有更好的办法。

幸运的是,确实有。对于这个问题,Graphics 类备受推崇。不仅因为它能实现我们想要的功能以及更多,还因为它存在于窗体的 PaintEventArgs 中,这对于在运行时显示图像、图表和其他内容至关重要。这个“WonderClass”非常棒,似乎是我们代码的焦点。

但在我们开始编写代码之前...
我们需要一个体面的 GUI!

GUI

创建一个新的 VB 项目(请注意,此应用程序在 Visual Studio 的 Express 版本中也可以实现)
step01.jpg

将其命名为 PocketWatchVB,然后单击“确定”。

当出现一个空白窗体时,更改
FormBorderStyleFixedSingle

我们这样做是为了用户无法调整窗体大小,从而避免将来可能出现的错误。

为了实现平滑的动画,将 DoubleBuffered 设置为 True。这将确保您不会出现任何动画闪烁或低质量问题。

step02.jpg

再次,请确保样式设置为 FixedSingle

step03.jpg

图像

在执行下一步之前,我建议您准备好要用作背景和表针的图片。您可以从下方下载,自己制作,或者使用源代码中的图片(SRC.zip\Watch\Resources)。

如果您打算自己制作图片,本文档适用的图片尺寸为 256x256。它们都应该有透明背景,并且表针的尺寸应略小于表盘(但图片尺寸仍必须为 256x256)。

资源导入

导入您应该已保存的四张图片,方法是更改 Form1BackgroundImage 并导入所有四张图片。

step04.jpg

将所有四张图片导入到 .resx 文件中。

step05.jpg

选择 (none)

无?在将图片导入到 Resources 后选择无的整个目的是为了避免在代码中处理外部路径,使程序更具可移植性,并使代码更简洁地引用资源。所以不要设置任何 BackgroundImage,这只是为了导入资源。

step06.jpg

将窗体的大小设置为 370x370。

这会将我们的图片放在窗体的正中央。只是为了美观。 :)

step7.jpg

检查点 1

如果您的窗体看起来像这样,做得好! ;)
关键在于这是一个空白窗体。为了支持“自制”的理念,所有操作都在运行时完成(实际上这样更快,并且更适合叠加图片)。

step8.jpg
是的,我使用了粘贴的图标。喜欢吗?

代码实现

为了在开始编码之前了解需要做什么,让我们使用一个表格。

步骤 1 计时器滴答
第二步 重绘窗体
步骤 3 绘制背景
步骤 4 查找小时
步骤 5 将小时格式化为 12 小时制
步骤 6 查找分钟
步骤 7 查找所有旋转角度
步骤 8 旋转秒针 - 叠加
步骤 9 旋转分针 - 叠加
第 10 步 旋转时针 - 叠加

可以清楚地看到,大部分代码将用于旋转和叠加时钟的指针,而程序的前半部分则用于达到那个点。

声明!

为了让一切正常工作,需要进行一些声明。这些是项目成功所必需的。

在声明区域导入这些

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)

在代码运行前声明我们的 BMP 有助于一切顺利运行。另一方面,我们在关闭窗体之前需要处理掉它们。为此,请添加一个 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() 事件处理程序中。这是我们实际“绘制”窗体的地方。我们的“画家”将是继承 PaintEventArgsGraphics 类,它允许我们“绘制”窗体。您也可以绘制控件、面板以及许多其他东西,但代码可能需要进行调整。

e.Graphics.DrawImage(WatchBMP, 0, 0)

首先,让我们将怀表绘制到窗体背面。
由于这在 Form1_paint() 事件处理程序内部,e 指的是 PaintEventArgs。此类允许我们访问将绘制窗体的 Graphics 画家。在这里,我们只是告诉“画家”在点 (0,0) 处绘制我们的图片(在 Resources 中)。

'make 12-hour instead of 24-hour

clockHour = Now.TimeOfDay.Hours

If clockHour > 12 Then

clockHour -= 12

ElseIf clockHour = 0 Then

clockHour = 12

End If

'Set the angles for minute and hour

hourAng = 30 * ClockHour
minAng = 6 * Now.TimeOfDay.Minutes
secAng = 6 * Now.Second

在我们让“画家”绘制时钟的指针之前,我们需要告诉他们如何以及在哪里绘制。所以这段代码会将标准的 24 小时制时间格式转换为常见的 12 小时制模拟格式。然后根据相应的公式计算角度,这并不难理解,只需记住有 12 小时,用 360 除以 12,然后告诉您的应用程序相应地乘以,以此类推。


注意:如果您还没有注意到,当我提到“画家”时,我指的是将用于“绘制”窗体的 Graphics 类。如果您不善于类比,请原谅我的类比 =)

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()

这个片段创建了一个 Matrix,在将更改应用于我们的“画家”之前,比直接使用 Graphics 类更容易进行操作。首先,Matrix 被定位并以必要的方式旋转,以确保时钟指针不会偏离中心,甚至不会超出屏幕。然后使用 e.Graphics.Transform = sec 将更改应用到我们的“画家”。在此之后,图像被绘制到窗体上,并且 Matrix 被释放以正确清空资源。

由于我们的时钟有三个指针,而且它们的工作方式相似,我们发现我们的代码也倾向于相似,但有一些不同。这就是其中一种情况。

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)。

快完成了!

现在我们的工作过程已经完成,我们需要一种方法来启动它们。

添加 Timer 的 tick 事件处理程序来启动这一切。

Private Sub Timer1_Tick(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles Timer1.Tick
Me.Refresh()
End Sub

好的,等等。只是刷新窗体?刷新窗体会导致它重新绘制自身。这会调用我们的 OnPaint 处理程序,它负责所有任务。所以,让我们看看这是否有效。运行窗体,时钟会短暂地空白,然后显示一张图片。更像是自制的图片。 =)

现在我们完成了

如果您一切正确,您的表应该看起来像这样。

Final.jpg

回顾

好吧,这很特别。一个听起来简单的课题,由于要求尽可能在运行时和/或从头开始完成而变得困难。可以使用 Matrix 来绘制窗体。一些死气沉沉的图片可以被赋予生命,一个没有任何控件的普通窗体可以被做成看起来像专业制作的用户控件。这是第一次,你可以无中生有。这就是编程的魅力。

© . All rights reserved.