Introduction
This article is meant to explain how to add animations to a Windows Form. The first section will briefly explain the process behind by designing a Windows Form. Next will be an example of drawing on a Form using the Graphics
class. Finally, the article will conclude with code that can either be compiled on the DOS prompt of the .NET Framework, or built using the separate files that comprise the Visual Studio project.
When working with Windows Forms, the Form
object is used to represent any window in your application. This includes the top-most main windows in an SDI (Single-Document Interface), as well as the parent and child windows of an MDI (Multiple Document Interface) application. To create a main window, you must:
- Derive a custom class from
System.Windows.Forms.Form
.
- Configure the application's
Main
method to call Application.Run()
, passing an instance of your new Form
derived class as an argument:
using System;
using System.Windows.Forms;
public class MainForm : Form
{
public MainForm(){}
public static int Main(string[] args)
{
Application.Run(new MainForm());
return 0;
}
}
}
In the world of Windows Forms, a blank form will often have controls dragged and dropped onto it. A control is an element on the form which has properties that are set. The dragging and dropping of the controls onto the design surface of Visual Studio 2005 to then set their properties cause the IDE to generate code that defines the Form file in one Form.cs file and one Form.Designer.cs file. But, suppose we want to use graphics on a form that we want to draw on a form or a control.
Furthermore, suppose we want to build another window inside of the main window in order to achieve animation. To draw on a control or form, you must first:
- Create a
Graphics
object by calling the System.Windows.Forms.CreateGraphics
method.
- Create a
Pen
object.
- Call a member of the
Graphics
class to draw on the control using the Pen
. Here is an example:
(File: DrawLine.cs; To compile: c:\Windows\Microsoft.NET\Framework\v2.0.50727>csc.exe /target:winexe DrawLine.cs.)
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
public class MainForm : System.Windows.Forms.Form
{
private System.ComponentModel.Container components;
public MainForm()
{
InitializeComponent();
CenterToScreen();
SetStyle(ControlStyles.ResizeRedraw, true);
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Text = "Fun with graphics";
this.Resize += new System.EventHandler(this.Form1_Resize);
this.Paint += new System.Windows.Forms.PaintEventHandler(this.MainForm_Paint);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new MainForm());
}
private void MainForm_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
Graphics g = this.CreateGraphics();
Pen p= new Pen(Color.Red, 7);
g.DrawLine(p, 1, 1, 100, 100);
}
private void Form1_Resize(object sender, System.EventArgs e)
{
}
}
Animation
If compiled on the DOS prompt of the .NET Framework directory, you will see a line that forms a 60 degree angle. Try to picture a parallel line where the ends are connected to form a square. If the line were to move counterclockwise, it would form a rotation that, if traced, would form a path. In video, the frame rate is the number of single frames per second the human eye sees. While it appears as normal motion, it is actually a set of frames, normally 60, that display per second while there is a horizontal and vertical sync rate. Graphics, however, portray motion by animation. Animation is accomplished by instantiating the System.Windows.Forms.Timer
class, which takes care of triggering a regular call to a method by a thread on the window. Note that animation occurs inside of the main window, so another window has to be built, one, in this case, that will rotate.
As stated, the Microsoft Visual Studio 2005 IDE generates code so that the properties of the controls are set to actually define the component as fields, while a control is an element on the form. If you download the example and run the solution file, you should see the animation. Because the .NET Framework 2.0 supports partial classes, we can sort of split two source code files down to form one Form file. The zip file for download contains the entire project in C#. The code below is meant to run on the command-line. The reader should note the program.cs, Form1.cs, and Form1.Desinger.cs files that comprise the project. After examining the source and how it is divided, examine the single source code file presented below:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
public partial class AnimForm : Form {
private float angle;
private Timer timer = new Timer();
private BufferedGraphics bufferedGraphics;
public AnimForm() {
BufferedGraphicsContext context = BufferedGraphicsManager.Current;
context.MaximumBuffer = new Size( this.Width + 1, this.Height + 1 );
bufferedGraphics = context.Allocate( this.CreateGraphics(),
new Rectangle( 0, 0, this.Width, this.Height) );
timer.Enabled = true;
timer.Tick += OnTimer;
timer.Interval = 20;
timer.Start();
}
private void OnTimer( object sender, System.EventArgs e ) {
angle ++;
if (angle > 359)
angle = 0;
Graphics g = bufferedGraphics.Graphics;
g.Clear( Color.Black );
Matrix matrix = new Matrix();
matrix.Rotate( angle, MatrixOrder.Append );
matrix.Translate( this.ClientSize.Width / 2,
this.ClientSize.Height/ 2, MatrixOrder.Append );
g.Transform = matrix;
g.FillRectangle( Brushes.Azure, -100, -100, 200, 200 );
bufferedGraphics.Render( Graphics.FromHwnd( this.Handle ) );
}
[System.STAThread]
public static void Main() {
Application.Run( new AnimForm() );
}
}
This example of animation is not meant as a substitute for studying the GDI+ library and the the .NET base classes involved. The code should be self-explanatory. Remember, the coordinates start at the upper left hand corner of a window. Comments and corrections are welcome.
References
- Practical .NET2 and C#2 by Patrick Smacchia