65.9K
CodeProject 正在变化。 阅读更多。
Home

FlickerFree - 使用 GDI+ 创建无闪烁图形

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.25/5 (11投票s)

2002年11月15日

1分钟阅读

viewsIcon

83013

downloadIcon

668

演示如何使用 GDI+ 创建无闪烁图形的代码示例。

Sample Image - FlickerFree.jpg

引言

首先我想说:“对不起我的拼写不好 - 但我会努力改进!”

在使用 GDI+ 创建移动对象/图形时,每次计时器滴答时都必须刷新屏幕 :-) 但这样图形就会闪烁 - 为了避免这种情况,可以使用双缓冲。在这个示例中,我将展示您需要什么才能实现无闪烁图形,以及如何使用 KeyEvent

使用代码

我使用了一个间隔为 40 毫秒的计时器,因为我们需要大约每秒 25 帧 (1000 毫秒 / 25 帧 = 40)。为了演示如何移动图形对象,我还内置了 KeyEvent

首先,您需要在类的构造函数中设置双缓冲

SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);

然后我们使用计时器每 40 毫秒刷新一次窗体

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();
}

接下来我们“监听”我们的键盘

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);
  }
}

并且我们必须重写 OnPaint 事件来绘制我们的对象

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);
}

为了计算我们的图形对象的新位置是否在客户端区域内,以及如果不在该区域内该怎么办,我使用了一个属性

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;
    }
  }
}

现在我们有了无闪烁的动画 ;-)

关注点

在我的示例的第一个版本中,我使用了 if() - else if() 来处理 KeyEvent。但那样一次只能使用一个键。使用 if() 处理每个键可以组合键以进行对角线移动。同样重要的是使用 this.Client.Widththis.Client.Height 而不是 this.Widththis.Height - 因为图形对象只能在客户端区域内移动,因此您可以计算移动的区域。

© . All rights reserved.