一般的 Windows Form 通常是运用各种控件来显示数据,然而如果您希望在窗体中加入特殊效果来凸显数据内容,那么图形与动画将是非常不错的选择。
一般来说,我们会使用 .Net Framework中 的 GDI+ 函式库来制作图形与动画效果。在 GDI+ 还没有推出之前,如果要产生二维的 向量图形、影像、以及印刷样式,必须使用旧版操作系统中的GDI。新的 GDI+ 是 Windows XP 的一部份,除了加入新功能之外,还最佳化现有功能以便具体改进 GDI(也就是旧版 Windows 包含的绘图装置接口)的效能。
程序范例
我们的程序范例示范了三种动画效果,分别是:眨眼效果、弹跳的球、以及文字闪烁,当程序执行时会自动展示第一种眨眼效果,如图表1到3所示。
运用之前「如何利用程序代码动态存取组件信息」的技巧,将组件的 AsmFQName 属性值指派给窗体的 Text 属性,并将先前已经加入项目资源的四张图片名称指派给数组,之后就使用此数组来示范眨眼效果,程序代码撰写于窗体的Load事件处理例程中,如下所示:
| private void Blog_DemoForm002_Load(object sender, EventArgs e) { AssemblyInfoClass myAssembly = new AssemblyInfoClass(); this.Text = myAssembly.AsmFQName; // 指派数组成员。 arrImages[0] = Properties.Resources.Eye1; arrImages[1] = Properties.Resources.Eye2; arrImages[2] = Properties.Resources.Eye3; arrImages[3] = Properties.Resources.Eye4; } |
如果您要使用 Visual C# 来制作「关于」对话框,建议先使用Visual Studio 2005所提供的模板来产生关于对话框窗体,然后再自订窗体所要呈现的内容(如图表4所示)。在此,我们选择将组件的相关信息填入窗体对应的控件,请于「关于」对话框窗体的 Load 事件处理例程中撰写下列程序代码:
| private void AboutBox_Load(object sender, EventArgs e) { AssemblyInfoClass myAssembly = new AssemblyInfoClass(); labelProductName.Text = "产品名称:" + myAssembly.Product; labelVersion.Text = "版本:" + myAssembly.Version; labelCopyright.Text = "版权宣告:" + myAssembly.Copyright; labelCompanyName.Text = "公司名称:" + myAssembly.Company; textBoxDescription.Text = "细部描述:" + myAssembly.Description; } |
要显示「关于」对话框,请替「说明」菜单项目的Click事件处理例程中撰写下列程序代码:
| private void toolStripMenuItem4_Click(object sender, EventArgs e) { // 显示关于对话框。 AboutBox MyAboutBox = new AboutBox(); // 设定关于对话框的启始位置。 MyAboutBox.StartPosition = FormStartPosition.CenterScreen; MyAboutBox.Show(); } |
当用户点选不同的选项按钮时,将会执行下列程序代码来显示不同的动画效果。这些程序代码撰写于选项按钮的 CheckedChanged 事件处理函式中,如下所列:
| private void RadioButtons_CheckedChanged(object sender, EventArgs e) { if(optWink.Checked) { tmrAnimation.Interval = WINK_TIMER_INTERVAL; } else if(optBall.Checked) { tmrAnimation.Interval = BALL_TIMER_INTERVAL; } else if(optText.Checked) { tmrAnimation.Interval = TEXT_TIMER_INTERVAL; } OnResize(EventArgs.Empty); } |
自订函式 RadioButtons_CheckedChanged 会叫用 OnResize 函式来产生不同的图形,请大家注意,我们系使用 Graphics 类别的 FillEllipse 方法来绘制球形,程序代码如下所列:
| protected override void OnResize(EventArgs ea) { if (optWink.Checked) { Graphics grfx = CreateGraphics(); // 重绘窗体。 this.Refresh(); } else if (optBall.Checked) { Graphics grfx = CreateGraphics(); grfx.Clear(BackColor); double dblRadius = Math.Min(ClientSize.Width / grfx.DpiX,ClientSize.Height / grfx.DpiY) / intBallSize; intBallRadiusX = (int)(dblRadius * grfx.DpiX); intBallRadiusY = (int)(dblRadius * grfx.DpiY); intBallMoveX = (int)(Math.Max(1, intBallRadiusX / intMoveSize)); intBallMoveY = (int)(Math.Max(1, intBallRadiusY / intMoveSize)); intBitmapWidthMargin = intBallMoveX; intBitmapHeightMargin = intBallMoveY; intBallBitmapWidth = 2 * (intBallRadiusX + intBitmapWidthMargin); intBallBitmapHeight = 2 * (intBallRadiusY + intBitmapHeightMargin); bitmap = new Bitmap(intBallBitmapWidth, intBallBitmapHeight); grfx = Graphics.FromImage(bitmap); grfx.Clear(BackColor); // 绘制球形。 grfx.FillEllipse(Brushes.Red, new Rectangle(intBallMoveX,intBallMoveY, 2 * intBallRadiusX, 2 * intBallRadiusY)); intBallPositionX = (int)(ClientSize.Width / 2); intBallPositionY = (int)(ClientSize.Height / 2); } else if (optText.Checked) { Graphics grfx = CreateGraphics(); grfx.Clear(BackColor); } } |
最后,利用定时器将图形连续重绘于窗体上,便产生了动画效果。程序代码撰写于定时器的 Tick 事件处理例程中,如下所示:
| private void tmrAnimation_Tick(object sender, EventArgs e) { // 眨眼效果。 if(optWink.Checked) { Graphics grfx = CreateGraphics(); // 将数组中之图形绘制在画面上。 grfx.DrawImage(arrImages[intCurrentImage],(int)( (ClientSize.Width - arrImages[intCurrentImage].Width) / 2), (int)((ClientSize.Height - arrImages[intCurrentImage].Height) / 2), arrImages[intCurrentImage].Width,arrImages[intCurrentImage].Height); intCurrentImage += j; if(intCurrentImage == 3) { j = -1; } else if(intCurrentImage == 0) { j = 1; } } else if(optBall.Checked) // 弹跳的球。 { Graphics grfx = CreateGraphics(); // 将球绘制在画面上。 grfx.DrawImage(bitmap,(int)(intBallPositionX - intBallBitmapWidth / 2), (int)(intBallPositionY - intBallBitmapHeight / 2), intBallBitmapWidth, intBallBitmapHeight); // 移动球的位置。 intBallPositionX += intBallMoveX; intBallPositionY += intBallMoveY; // 球碰到左右边界。 if(intBallPositionX + intBallRadiusX >= ClientSize.Width || intBallPositionX - intBallRadiusX <= 0) { intBallMoveX = -intBallMoveX; SystemSounds.Beep.Play(); } // 球碰到上下边界。 if(intBallPositionY + intBallRadiusY >= ClientSize.Height || intBallPositionY - intBallRadiusY <= 75) { intBallMoveY = -intBallMoveY; SystemSounds.Beep.Play(); } } else if (optText.Checked) // 闪动文字。 { Graphics grfx = CreateGraphics(); // 设定文字的字型与大小。 Font font = new Font("Microsoft Sans Serif", 48, FontStyle.Bold, GraphicsUnit.Point); // 设定要显示的文字。 string strText = "章立民研究室"; SizeF sizfText = new SizeF(grfx.MeasureString(strText, font)); // X坐标与Y坐标的配对。 PointF ptfTextStart = new PointF((float)(ClientSize.Width - sizfText.Width) / 2, (float)(ClientSize.Height - sizfText.Height) / 2); PointF ptfGradientStart = new PointF(0, 0); PointF ptfGradientEnd = new PointF(intCurrentGradientShift, 200); // 设定笔刷。 LinearGradientBrush grBrush = new LinearGradientBrush(ptfGradientStart, ptfGradientEnd, Color.Blue, BackColor); // 将文字绘制在画面上。 grfx.DrawString(strText, font, grBrush, ptfTextStart); // 以不同的坐标绘制文字,造成闪动效果。 intCurrentGradientShift += intGradiantStep; if (intCurrentGradientShift == 500) { intGradiantStep = -5; } else if (intCurrentGradientShift == -50) { intGradiantStep = 5; } } } |




