Visual C# 2005 - 利用程序代码制作简单动画效果

 

一般的 Windows Form 通常是运用各种控件来显示数据,然而如果您希望在窗体中加入特殊效果来凸显数据内容,那么图形与动画将是非常不错的选择。 

 

一般来说,我们会使用 .Net Framework GDI+  函式库来制作图形与动画效果。在 GDI+  还没有推出之前,如果要产生二维的 向量图形、影像、以及印刷样式,必须使用旧版操作系统中的GDI。新的 GDI+ Windows XP 的一部份,除了加入新功能之外,还最佳化现有功能以便具体改进 GDI(也就是旧版 Windows 包含的绘图装置接口)的效能。 

 

程序范例 


图表1 


图表2 

 

图表3 

我们的程序范例示范了三种动画效果,分别是:眨眼效果、弹跳的球、以及文字闪烁,当程序执行时会自动展示第一种眨眼效果,如图表13所示。 

 

运用之前「如何利用程序代码动态存取组件信息」的技巧,将组件的 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;
}

 

图表4 

如果您要使用 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;
  }
 }
}

 

posted on 2006-11-07 17:30  章立民研究室  阅读(3810)  评论(1编辑  收藏  举报

导航