A simple app demonstrates animation of WinForms using GDI+, a Paint handler and a Forms.Timer category 'KB', language C#, created 19-Nov-2009, version V1.2 (28-Feb-2010), by Luc Pattyn |
License: The author hereby grants you a worldwide, non-exclusive license to use and redistribute the files and the source code in the article in any way you see fit, provided you keep the copyright notice in place; when code modifications are applied, the notice must reflect that. The author retains copyright to the article, you may not republish or otherwise make available the article, in whole or in part, without the prior written consent of the author. Disclaimer: This work is provided “as is”, without any express or implied warranties or conditions or guarantees. You, the user, assume all risk in its use. In no event will the author be liable to you on any legal theory for any special, incidental, consequential, punitive or exemplary damages arising out of this license or the use of the work or otherwise. |
This article describes the proper way to do WinForms animation, i.e. showing a Form that changes over time;
it uses GDI+
, a double-buffered panel, and a System.Windows.Forms.Timer
;
and it performs all painting/drawing inside the Paint
handler.
There are several steps to correctly draw something; it does not matter how complex the paint job is: from a single line, to a complex drawing, or a real work of art.
To make sure it all becomes visible on the screen and gets repainted automatically when moving, resizing, minimizing/maximizing/restoring or uncovering your Form, one should follow these steps:
PaintEventArgs
parameter, so why create a new one?
BTW: if you need to create some objects (Fonts, Pens, Brushes, ...) either create them inside the Paint handler and don't forget to call Dispose() on them (one must call dispose on instances of a class that offers such method), or better yet create them only once and keep them alive in class members, this avoids creating a lot of new objects, followed by disposing and collecting them.
The environment used is the Microsoft .NET Framework (version 2.0 or above) and the C# programming language. The demo program shows a Form with some GUI Controls and a Panel onto which an image is drawn. When the "Animate" button is pressed, the image grows until it fills the Panel. The number of steps in the animation, and the duration of each step (the timer period), can be selected through TextBoxes.
Click the image to see the animation (uses a big GIF file, almost 2MB).
This is the bulk of the code:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace Animation1 {
public partial class Form1 : Form {
Bitmap image;
Timer timer;
int step;
int steps;
public Form1() {
InitializeComponent();
// get image
image=new Bitmap("VisualStudio2008.png");
steps=1;
// now draw it
panel1.Paint+=new PaintEventHandler(panel1_Paint);
panel1.Invalidate();
}
void panel1_Paint(object sender, PaintEventArgs e) {
// the one animation parameter here is "step"
int wOrig=image.Width;
int hOrig=image.Height;
int wFinal=panel1.Width;
int hFinal=panel1.Height;
// interpolate between initial and final image
int w=(wOrig*(steps-step)+wFinal*step)/steps;
int h=(hOrig*(steps-step)+hFinal*step)/steps;
int x=(wFinal-w)/2;
int y=(hFinal-h)/2;
// now paint image
e.Graphics.DrawImage(image, x, y, w, h);
}
private void btnAnimate_Click(object sender, EventArgs e) {
if (step!=0) {
step=steps; // cancel the animation
} else {
// get parameters and validate them
if (!int.TryParse(tbSteps.Text, out steps) || steps<1 || steps>1000) steps=50;
tbSteps.Text=steps.ToString();
int delay;
if (!int.TryParse(tbDelay.Text, out delay) || delay<10 || delay>1000) delay=17;
tbDelay.Text=delay.ToString();
// paint the image on the Panel, and start timer for animation
panel1.Invalidate();
timer=new Timer();
timer.Interval=delay;
timer.Tick+=new EventHandler(timer_Tick);
timer.Start();
btnAnimate.Text="Cancel";
}
}
void timer_Tick(object sender, EventArgs e) {
step++;
if (step>steps) {
// terminate the animation
step=0;
timer.Stop();
btnAnimate.Text="Animate";
}
panel1.Invalidate();
}
}
//####################################################################################
// DoubleBufferedPanel is a panel that uses double buffering to avoid flicker.
//####################################################################################
public class DoubleBufferedPanel : Panel {
public DoubleBufferedPanel() {
DoubleBuffered=true;
}
}
}
The project files are available here; they target Visual Studio 2008.
A few simple rules suffice to paint and even animate just about anything.
Perceler |
Copyright © 2012, Luc Pattyn |
Last Modified 02-Sep-2013 |