2010-04-09 20 views
9

Estoy trabajando en el tipo de programa de dibujo, pero tengo un problema con el parpadeo mientras muevo el cursor del mouse mientras dibujo una línea de banda elástica. Espero que me puedan ayudar a eliminar ese parpadeo de línea, aquí está el código:Gráficos de C# parpadeando

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace GraphicsTest 
{ 
    public partial class Form1 : Form 
    { 
     int xFirst, yFirst; 
     Bitmap bm = new Bitmap(1000, 1000); 
     Graphics bmG; 
     Graphics xG; 
     Pen pen = new Pen(Color.Black, 1); 
     bool draw = false; 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      bmG = Graphics.FromImage(bm); 
      xG = this.CreateGraphics(); 
      bmG.Clear(Color.White); 
     } 

     private void Form1_MouseDown(object sender, MouseEventArgs e) 
     { 
      xFirst = e.X; 
      yFirst = e.Y; 
      draw = true; 
     } 

     private void Form1_MouseUp(object sender, MouseEventArgs e) 
     { 
      bmG.DrawLine(pen, xFirst, yFirst, e.X, e.Y); 
      draw = false; 
      xG.DrawImage(bm, 0, 0); 
     } 

     private void Form1_MouseMove(object sender, MouseEventArgs e) 
     { 
      if (draw) 
      { 
       xG.DrawImage(bm, 0, 0); 
       xG.DrawLine(pen, xFirst, yFirst, e.X, e.Y); 
      } 
     } 

     private void Form1_Paint(object sender, PaintEventArgs e) 
     { 
      xG.DrawImage(bm, 0, 0); 
     } 
    } 
} 
+3

¿Hay memoria intermedia doble en sus formularios o controles? – FrustratedWithFormsDesigner

+3

No sirvió de nada. – Jeff

Respuesta

23

En primer lugar no utilizar CreateGraphics() a menos que sea absolutamente necesario. Enlace un controlador de eventos al OnPaint y llame al Invalidate() cuando desee actualizar la superficie.

Si no desea que parpadee, tendrá que duplicar la memoria intermedia de su superficie de dibujo. La forma más fácil de hacerlo es establecer la propiedad DoubleBuffered de su formulario en True.

Lo recomendaría encarecidamente si planea ampliar esto para hacer su dibujo en el control PictureBox. PictureBox tiene doble buffer por defecto y le permite controlar su región de dibujo de forma mucho más simple.

En código:

public partial class Form1 : Form 
    { 
    int xFirst, yFirst; 
    Bitmap bm = new Bitmap(1000, 1000); 
    Graphics bmG; 
    Pen pen = new Pen(Color.Black, 1); 
    bool draw = false; 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     bmG = Graphics.FromImage(bm); 
     bmG.Clear(Color.White); 
    } 

    private void Form1_MouseDown(object sender, MouseEventArgs e) 
    { 
     xFirst = e.X; 
     yFirst = e.Y; 
     draw = true; 
    } 

    private void Form1_MouseUp(object sender, MouseEventArgs e) 
    { 
     bmG.DrawLine(pen, xFirst, yFirst, e.X, e.Y); 
     draw = false; 
     Invalidate(); 
    } 

    private void Form1_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (draw) 
     { 
      Invalidate(); 
     } 
    } 

    private void Form1_Paint(object sender, PaintEventArgs e) 
    { 
     if (draw) { 
      e.Graphics.DrawImage(bm, 0, 0); 
      e.Graphics.DrawLine(pen, xFirst, yFirst, e.X, e.Y); 
     } else { 
      e.Graphics.DrawImage(bm, 0, 0); 
     } 
    } 
} 

Editar:

Otra cuestión, que está creando un Pen miembro privado. Los bolígrafos (y los pinceles, así como muchos objetos GDI +) representan controladores para objetos no administrados que deben eliminarse o, de lo contrario, su programa perderá. O envuélvalos en las declaraciones using (la forma preferida y segura para excepciones) o deséchelos explícitamente en el método Dispose del formulario.

Alternativamente, en System.Drawing puede acceder a algunos bolígrafos y brochas preconstruidos que no necesitan (ni deben) desecharse. Los utilizan como:

private void Form1_Paint(object sender, PaintEventArgs e) 
    { 
     if (draw) { 
      e.Graphics.DrawImage(bm, 0, 0); 
      e.Graphics.DrawLine(Pens.Black, xFirst, yFirst, e.X, e.Y); 
     } else { 
      e.Graphics.DrawImage(bm, 0, 0); 
     } 
    } 
+0

Gracias por una respuesta y por una sugerencia, intentaré solucionarlo. – Jeff

+0

He solucionado un pequeño problema con el código, puedes deshacerte de tu objeto xG y usar la propiedad 'e.Graphics' de PaintEventArgs en el evento paint para obtener el contexto gráfico de tu formulario. –

+0

Sí, funciona. Muchas gracias. Ahora entiendo el uso de Invalidate() también. Bonito. – Jeff

6

La razón por la que parpadea es el que está dibujando el fondo (que se muestra inmediatamente en la pantalla, secándose la línea) y luego superponer la línea. Por lo tanto, la línea sigue desapareciendo y apareciendo, dando una pantalla parpadeante.

La mejor solución para esto se llama Doble Buffering. Lo que debes hacer es dibujar toda la imagen en un mapa de bits "fuera de pantalla", y solo mostrarla en la pantalla cuando se complete. Como solo muestra la imagen completa, no hay efecto de parpadeo. Debería poder establecer esto. DoubleBuffered = true para que WinForms haga todo el trabajo por usted.

NB: Realmente no debería dibujar fuera de su controlador de pintura; lo ideal sería que invalide() el área que necesita volver a dibujar, y luego su manejador de pintura volverá a dibujar esa área (con líneas superpuestas, etc. según sea necesario))

+0

Gracias por la explicación detallada – Jeff

2

Código fijo y de trabajo.

public partial class Form1 : Form 
{ 
    int x1, y1, x2, y2; 
    bool drag = false; 

    Bitmap bm = new Bitmap(1000, 1000); 
    Graphics bmg; 


    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     bmg = Graphics.FromImage(bm); 
    } 

    private void pictureBox_MouseDown(object sender, MouseEventArgs e) 
    { 
     drag = true; 
     x1 = e.X; 
     y1 = e.Y; 
    } 

    private void pictureBox_MouseUp(object sender, MouseEventArgs e) 
    { 
     drag = false; 

     bmg.DrawLine(Pens.Black, x1, y1, e.X, e.Y); 
     pictureBox.Invalidate(); 
    } 

    private void pictureBox_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (drag) 
     { 
      x2 = e.X; 
      y2 = e.Y; 
      pictureBox.Invalidate(); 
     } 
    } 

    private void pictureBox_Paint(object sender, PaintEventArgs e) 
    { 
     if (drag) { 
      e.Graphics.DrawImage(bm, 0, 0); 
      e.Graphics.DrawLine(Pens.Black, x1, y1, x2, y2);    
     } 
     else { 
      e.Graphics.DrawImage(bm, 0, 0); 
     } 
    } 
} 
+0

Cambié mi solución a esto y el evento de mover mi mouse dejó de funcionar, lol – Pavel

Cuestiones relacionadas