2010-10-30 11 views
8

No estoy seguro de cómo dibujar un rectángulo (no relleno) cuando arrastro mi mousedown mientras hago clic con el botón izquierdo del mouse.Cómo dibujar un rectángulo en MouseDown/Move C#

tengo esto hasta ahora

  private void canevas_MouseDown(object sender , MouseEventArgs e) 
      { 
        if(e.Button == MouseButtons.Left) 
        { 
          _topLeft = new Point(e.X , e.Y); 
          _drawing = true; 
        } 
      } 

      private void canevas_MouseMove(object sender , MouseEventArgs e) 
      { 
        if(_drawing) 
        { 
          Rectangle rec = new Rectangle(_topLeft.X , _topLeft.Y , (e.X - _topLeft.X) , (e.Y - _topLeft.Y)); 
          canevas.CreateGraphics().DrawRectangle(Pens.Black , rec); 
        } 
      } 

Pero los problemas de TI que no quiero todos los rectángulos que aparecen

Respuesta

19

algo de código para ir con la respuesta correcta de Ed:

Point startPos;  // mouse-down position 
    Point currentPos; // current mouse position 
    bool drawing;  // busy drawing 
    List<Rectangle> rectangles = new List<Rectangle>(); // previous rectangles 

    private Rectangle getRectangle() { 
     return new Rectangle(
      Math.Min(startPos.X, currentPos.X), 
      Math.Min(startPos.Y, currentPos.Y), 
      Math.Abs(startPos.X - currentPos.X), 
      Math.Abs(startPos.Y - currentPos.Y)); 
    } 

    private void canevas_MouseDown(object sender, MouseEventArgs e) { 
     currentPos = startPos = e.Location; 
     drawing = true; 
    } 

    private void canevas_MouseMove(object sender, MouseEventArgs e) { 
     currentPos = e.Location; 
     if (drawing) canevas.Invalidate(); 
    } 

    private void canevas_MouseUp(object sender, MouseEventArgs e) { 
     if (drawing) { 
      drawing = false; 
      var rc = getRectangle(); 
      if (rc.Width > 0 && rc.Height > 0) rectangles.Add(rc); 
      canevas.Invalidate(); 
     } 
    } 

    private void canevas_Paint(object sender, PaintEventArgs e) { 
     if (rectangles.Count > 0) e.Graphics.DrawRectangles(Pens.Black, rectangles.ToArray()); 
     if (drawing) e.Graphics.DrawRectangle(Pens.Red, getRectangle()); 
    } 

para obtener un 'Canevas' que ha de doble búfer encendidas , para que la pintura no parpadee, use Proyecto + Agregar nuevo elemento, seleccione "Clase" y pegue este código:

using System; 
using System.Windows.Forms; 

class Canvas : Panel { 
    public Canvas() { 
     this.DoubleBuffered = true; 
     this.SetStyle(ControlStyles.ResizeRedraw, true); 
    } 
} 

Compilar. Arrastre el nuevo control desde la parte superior de la caja de herramientas a su formulario, reemplazando las 'canevas' originales. Actualice los controladores de eventos en consecuencia.

+1

gracias, lo tenía correctamente pero me ayudó con la resistencia revertida. :) – Burnzy

+0

Todo parece estar bien hasta ahora, excepto el parpadeo, alguna idea? – Burnzy

+0

Dejé un comentario, ¿estás usando e.Graphics en el evento Paint? Probé este código, está libre de parpadeos incluso sin doble buffering. –

5

No llame CreateGraphics. En MouseDown, almacena la posición inicial y una bandera para indicar que estás dibujando. En MouseMove, revisa la bandera. Si está dibujando, cree el rectángulo relativo a la posición de inicio y almacénelo (que ya está haciendo), y luego llame a Invalidate(). Todo su código de dibujo estará en OnPaint() (canvas.Paint desde fuera de la clase, aunque probablemente crearía mi propia clase para esto para evitar ensuciar su código de formulario con esto).

El dibujo debe hacerse en su controlador de pintura (OnPaint). Si dibuja fuera de eso, su objeto gráfico no se borra (de ahí los múltiples rectángulos) y cualquier cosa que dibuje puede borrarse en momentos aparentemente impares cuando su ventana recibe un mensaje WM_PAINT.

EDITAR: Ahora que tiene problemas de rendimiento, hay algunas maneras simples de optimizar un poco la pintura. En primer lugar, Invalidate tomará opcionalmente un rectángulo como argumento para que no tenga que repintar todo el control. En segundo lugar, si está dibujando en MouseMove, va a dibujar bastante. Usar el doble almacenamiento en memoria intermedia también ayudará mucho, simplemente establezca la propiedad DoubleBuffered en true o agréguela al valor ControlStyles llamando a SetStyle en el control.

+0

Por cierto, no estoy muy seguro de lo que es invalidante para – Burnzy

+0

@Burnzy, Invalidate invalida los gráficos del control para que Windows vuelva a invocar la operación de pintura. (Básicamente una vez que el control se invalida, necesita volver a dibujarse) –

+0

¿Alguna idea de cómo solucionar el problema de parpadeo? – Burnzy

0

Bien ahora tengo esto, está funcionando pero, parpadea mucho, incluso con doble almacenamiento en búfer.

  private void canevas_MouseDown(object sender , MouseEventArgs e) 
      { 
        _topLeft = new Point(e.X , e.Y); 
        if(e.Button == MouseButtons.Left) 
        { 
          _topLeft = new Point(e.X , e.Y); 
          _drawing = true; 
        } 
      } 

      private void canevas_MouseUp(object sender , MouseEventArgs e) 
      { 
        _drawing = false; 
        _bottomRight = new Point(e.X , e.Y); 
        int newX = _topLeft.X - (_bottomRight.X - _topLeft.X)/2; 
        int newY =_topLeft.Y + (_bottomRight.Y - _topLeft.Y)/2; 
        MouseEventArgs me = new MouseEventArgs(MouseButtons.Left , 1 , newX , newY , 0); 

        canevas_MouseClick(canevas , me); 
      } 

      private void canevas_MouseMove(object sender , MouseEventArgs e) 
      { 
        if(_drawing) 
        { 
          _bottomRight = new Point(e.X , e.Y); 
          canevas.Invalidate(); 
        } 
      } 

Y luego en la pintura

  private void canevas_Paint(object sender , PaintEventArgs e) 
      { 
        Graphics g = canevas.CreateGraphics(); 
        g.DrawImage(_buffer , new Rectangle(0 , 0 , canevas.Width , canevas.Height)); 
        g.DrawRectangle(Pens.White , new Rectangle(_topLeft.X , _topLeft.Y , (_bottomRight.X - _topLeft.X) , (_bottomRight.Y - _topLeft.Y))); 
      } 
+2

* No * use CreateGraphics(). Usa e.Graphics en el evento Paint. –

0
public Form1() 
    { 
     InitializeComponent(); 
     // Use the cross "+" cursor 
     this.Cursor = System.Windows.Forms.Cursors.Cross; 
     // This will reduce flicker (Recommended) 
     this.DoubleBuffered = true; 
    } 

Agregue este código a su formulario. ¡Esto puede reducir el parpadeo!

Cuestiones relacionadas