我正在尝试实现以下方法: 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);
这是你的意思吗?因为它仍在闪烁?
答案 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作为渲染引擎。