双缓冲C#

时间:2010-06-18 13:59:06

标签: c# graphics doublebuffered

我正在尝试实现以下方法: void Ball :: DrawOn(Graphics g);

该方法应绘制球的所有先前位置(存储在队列中),最后绘制当前位置。我不知道这是否重要,但我使用g.DillEllipse(...)打印以前的位置,使用g.FillEllipse(...)打印当前位置。

问题是,你可以想象有很多绘图需要完成,因此显示开始闪烁很多。我曾经寻找过双缓冲的方法,但我能找到的就是这两种方式:

1)System.Windows.Forms.Control.DoubleBuffered = true;

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

在尝试使用第一个时,我得到一个错误,解释说在此方法中,由于其保护级别,属性DoubleBuffered无法访问。虽然我无法想象如何使用SetStyle方法。

是否有可能将缓冲区加倍,而 所有访问 我所拥有的是我在方法中输入的图形对象?

先谢谢,

编辑: 我创建了以下类

namespace doubleBuffer
{
    class BufferedBall : System.Windows.Forms.Form{
        private Ball ball;
        public BufferedBall(Ball ball)
        {
            this.ball = ball;
        }

    public void DrawOn(Graphics g){
        this.DoubleBuffered = true;
        int num = 0;
        Rectangle drawArea1 = new Rectangle(5, 35, 30, 100);
        LinearGradientBrush linearBrush1 =
        new LinearGradientBrush(drawArea1, Color.Green, Color.Orange, LinearGradientMode.Horizontal);
        Rectangle drawArea2 = new Rectangle(5, 35, 30, 100);
        LinearGradientBrush linearBrush2 =
           new LinearGradientBrush(drawArea2, Color.Black, Color.Red, LinearGradientMode.Vertical);
        foreach (PointD point in ball.previousLocations)
        {
            Pen myPen1;
            if (num % 3 == 0)
                myPen1 = new Pen(Color.Yellow, 1F);
            else if (num % 3 == 1)
                myPen1 = new Pen(Color.Green, 2F);
            else
                myPen1 = new Pen(Color.Red, 3F);
            num++;
            myPen1.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
            myPen1.StartCap = System.Drawing.Drawing2D.LineCap.RoundAnchor;
            myPen1.EndCap = System.Drawing.Drawing2D.LineCap.AnchorMask;
            g.DrawEllipse(myPen1, (float)(point.X - ball.radius), (float)(point.Y + ball.radius), (float)(2 * ball.radius), (float)(2 * ball.radius));
        }
        if ((ball.Host.ElapsedTime * ball.Host.FPS * 10) % 2 == 0){
            g.FillEllipse(linearBrush1, (float)(ball.Location.X - ball.radius), (float)(ball.Location.Y + ball.radius), (float)(2 * ball.radius), (float)(2 * ball.radius));
        }else{
            g.FillEllipse(linearBrush2, (float)(ball.Location.X - ball.radius), (float)(ball.Location.Y + ball.radius), (float)(2 * ball.radius), (float)(2 * ball.radius));
        }
    }
}

}

并且球drawOn看起来像这样:

new BufferedBall(this).DrawOn(g);
这是你的意思吗?因为它仍在闪烁?

5 个答案:

答案 0 :(得分:3)

Form类将DoubleBuffered属性公开为受保护。 http://msdn.microsoft.com/en-us/library/system.windows.forms.control.doublebuffered.aspx但是,由于您从Form派生了表单,因此可以使用它。

答案 1 :(得分:3)

this.DoubleBuffered = true;

没关系,但你将此语句移动到构造函数中。双缓冲需要设置,Windows Forms必须创建一个缓冲区,必须在 paint事件运行之前完成。构造函数是理想的。

答案 2 :(得分:2)

为控件派生类的双缓冲设置样式的一种更简单的方法是使用反射。见这里:http://www.csharp-examples.net/set-doublebuffered/

这样可以省去为控件创建受保护属性的子类化步骤。

答案 3 :(得分:1)

每次重绘时都不需要将DoubleBuffered设置为true。绘制完成后不会禁用它。只需从DrawOn中删除该行并在构造函数或Forms Designer中设置它并检查结果。将值设置为false会产生明显的闪烁,而设置为true则不会。

我尝试了一个表单,其中一个计时器强制每毫秒重绘一次,当DoubleBuffered为真时没有发现闪烁:

private int yDir = 1,xDir=1;
int step = 1;

private void timer1_Tick(object sender, EventArgs e)
{
    if (ball.Location.Y >= this.Height-50)
        yDir =   -1 ;
    if (ball.Location.X >= this.Width-50) 
        xDir= -1 ;

    ball.MoveBy(xDir*step,yDir*step);
    ball.Host.ElapsedTime++;
    this.Invalidate();
 }

private void DoubleBufferedBall_Paint(object sender, PaintEventArgs e)
{                      
        DrawOn(e.Graphics);
}

答案 4 :(得分:0)

我将为你抛出的另一个选项是将所有绘图都绘制到Bitmap,然后在OnPaint方法中,只需将该Bitmap绘制到窗体即可。

它的手册,但它可以让你完全控制。我已经在我的一些宠物项目上取得了一些成功。

您也可能想要查看XNA - 这可能对您的项目来说太过分了,但您可以在WinForms中使用XNA作为渲染引擎。