FlickerFree - Creating flicker-free graphics with GDI+






4.25/5 (11 votes)
Nov 15, 2002
1 min read

82754

668
Sample code on how to create flicker-free graphics with GDI+.
Introduction
First I want to say: "Sorry about my spelling - but I'll try to become better!"
When you create moving objects/graphics using GDI+, you have to refresh the screen every time the timer ticks :-) But then the graphics begin to flicker - to avoid this you can use Double-Buffering. In this sample, I'll show what you need for flicker-free-graphics and also how to use KeyEvent
s.
Using the code
I've used a timer with an interval of 40 milliseconds because we need about 25 frames per second (1000 milliseconds / 25 frames = 40). To demonstrate how to move the graphics-object I have also built in KeyEvent
s.
At first you have to set Double-Buffering in the constructor of your class:
SetStyle(ControlStyles.DoubleBuffer, true); SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true);
Then we use a timer to refresh the form every 40 milliseconds:
private System.Windows.Forms.Timer t; t = new Timer(); t.Interval = 40; t.Tick += new System.EventHandler(TimerOnTick); t.Enabled = true; private void TimerOnTick(object sender, System.EventArgs e) { this.Refresh(); // #### 84: Refresh the form this.Text = DateTime.Now.ToString(); this.Text += " " + this.PlayerPosition.ToString(); }
Next we "listen" to our keyboard:
this.KeyDown += new System.Windows.Forms.KeyEventHandler(OnKeyPress); private void OnKeyPress(object sender, System.Windows.Forms.KeyEventArgs e) { // #### 84: When the Left-Cursor has been pressed if(e.KeyValue == 37) { this.PlayerPosition = new Point(this.PlayerPosition.X - this.playerSize.Width, this.PlayerPosition.Y); } // #### 84: When the Up-Cursor has been pressed if(e.KeyValue == 38) { this.PlayerPosition = new Point(this.PlayerPosition.X, this.PlayerPosition.Y - this.playerSize.Width); } // #### 84: When the Right-Cursor has been pressed if(e.KeyValue == 39) { this.PlayerPosition = new Point(this.PlayerPosition.X + this.playerSize.Height, this.PlayerPosition.Y); } // #### 84: When the Down-Cursor has been pressed if(e.KeyValue == 40) { this.PlayerPosition = new Point(this.PlayerPosition.X, this.PlayerPosition.Y + this.playerSize.Height); } }
And we have to overwrite the OnPaint
event to draw our object:
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { e.Graphics.FillRectangle(new SolidBrush(Color.Red), this.PlayerPosition.X, this.PlayerPosition.Y, this.playerSize.Width, this.playerSize.Height); }
To calculate if the new position of our graphics-object is in the client area and what to do if not, I've used a property:
private Point PlayerPosition { get { return this.playerPosition; } set { if(value.X < 0) { this.playerPosition.X = this.ClientSize.Width - this.playerSize.Width; } else if(value.X + this.playerSize.Width > this.ClientSize.Width) { this.playerPosition.X = 0; } else { this.playerPosition.X = value.X; } if(value.Y < 0) { this.playerPosition.Y = this.ClientSize.Height - this.playerSize.Height; } else if(value.Y + this.playerSize.Height > this.ClientSize.Height) { this.playerPosition.Y = 0; } else { this.playerPosition.Y = value.Y; } } }
Now we have a flicker-free animation ;-)
Points of interest
In the first version of my sample I used if()
- else if()
for the KeyEvent
. But then one key worked at a time. Using if()
for every key makes it possible to combine the keys for a diagonal movement. It's also important to use this.Client.Width
and this.Client.Height
instead of this.Width
and this.Height
- because the graphics-object can only be moved in the client-area and so you can calculate areas for the movement.