65.9K
CodeProject is changing. Read more.
Home

FlickerFree - Creating flicker-free graphics with GDI+

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.25/5 (11 votes)

Nov 15, 2002

1 min read

viewsIcon

82754

downloadIcon

668

Sample code on how to create flicker-free graphics with GDI+.

Sample Image - FlickerFree.jpg

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 KeyEvents.

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 KeyEvents.

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.