Visual C# 2005 - 如何利用程式碼製作簡單動畫效果

摘要: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;
  }
 }
}