2010-06-18 16 views
5

Estoy tratando de implementar el siguiente método: void Ball :: DrawOn (Graphics g);Doble buffering C#

El método debe dibujar todas las ubicaciones previas (almacenadas en una cola) de la bola y finalmente la ubicación actual. No sé si eso importa, pero imprimo las ubicaciones anteriores usando g.DrawEllipse (...) y la ubicación actual usando g.FillEllipse (...).

La cuestión es que, como se podría imaginar, hay que hacer un gran esfuerzo y, por lo tanto, la pantalla comienza a parpadear mucho. Había buscado una forma de duplicar el búfer, pero todo lo que pude encontrar es estas 2 formas:

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

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

al intentar utilizar el primero, aparece un error que explica que en este método, la propiedad DoubleBuffered es inaccesible debido a su nivel de protección. Aunque no puedo entender cómo usar el método SetStyle.

¿Es posible en absoluto a la memoria intermedia doble, mientras que todo el acceso que tengo es que el Objeto de Gráficos consigo como entrada en el método?

Gracias de antemano,

Editar: que había creado la siguiente clase

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

}

y la pelota drawOn se ve así:

new BufferedBall(this).DrawOn(g); 

es eso ¿lo que quisiste decir? porque todavía está parpadeando?

+0

Bueno, el modo SetStyle() es correcto, y lo estás haciendo correctamente. AFAIK, la propiedad DoubleBuffered no se debe usar (se prefiere SetStyle), pero siempre se puede subclasificar el Control/Formulario/lo que sea y usarlo allí (está protegido). – sunside

Respuesta

3

Form la clase tiene la propiedad DoubleBuffered expuesta como protegida. http://msdn.microsoft.com/en-us/library/system.windows.forms.control.doublebuffered.aspx pero dado que deriva su formulario de Form puede usarlo.

+0

No, está protegido. – LmSNe

+2

sí, pero se deriva de Formulario. Al igual que cuando creas la aplicación básica de winforms crea Form1 que proviene de Form. Puedes acceder desde allí. De lo contrario, siempre puede crear un contenedor que expone esta propiedad. – Andrey

1

Una forma más sencilla de establecer el estilo para el doble almacenamiento en búfer de las clases derivadas de Control es utilizar la reflexión. Vea aquí: http://www.csharp-examples.net/set-doublebuffered/

Eso le ahorraría el paso de crear subclases de un control solo para establecer una propiedad protegida.

+0

Pero eso necesitaría acceso al objeto from del que estoy dibujando, ¿verdad? Todo el acceso que tengo es al objeto Graphics que se proporciona como parámetro para la función. ¿Es posible la reflexión en tal situación? – LmSNe

+0

Sí. Se puede hacer a través de la reflexión con solo unas pocas líneas de código: http://stackoverflow.com/questions/76993/how-to-double-buffer-net-controls-on-a-form –

2
this.DoubleBuffered = true; 

Eso está bien, pero que tienen para mover esta declaración al constructor. El búfer doble requiere configuración, Windows Forms tiene que crear un búfer, debe hacerse antes de se ejecuta el evento de pintura. El constructor es ideal.

1

No necesita establecer DoubleBuffered en verdadero cada vez que vuelve a dibujar. No está deshabilitado cuando el dibujo está terminado. Simplemente elimine la línea de DrawOn y configúrela en el constructor o en el Diseñador de formularios y verifique los resultados. Establecer el valor en falso produce un parpadeo significativo mientras que establecer en verdadero no lo hace.

me trataron su código en un formulario en el que un contador de tiempo obliga a volver a dibujar cada milisegundo y notamos sin parpadeo cuando DoubleBuffered es cierto:

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

Otra opción, que voy a tirar para usted, es hacer todo su dibujo en un mapa de bits, y luego en el método OnPaint, simplemente dibuja ese mapa de bits en el formulario.

Su manual, pero le da un control total. Lo he usado con cierto éxito en algunos de mis proyectos favoritos.

También es posible que desee examinar XNA, puede que sea excesivo para su proyecto aquí, pero puede usar XNA en WinForms como motor de representación.

+0

¿Es eso lo que querías decir? public void DrawOn (Gráficos g) { Bitmap bitmap = new Mapa de bits (800, 600, g); Gráficos g1 = Graphics.FromImage (mapa de bits); // dibujo a g1 ... g.DrawImage (mapa de bits, nuevo punto (0, 0)); } Porque esto todavía parpadea. – LmSNe

+0

Sí, lo es, pero no estoy seguro de por qué todavía parpadea para usted. – Nate