2010-11-12 13 views
8

Este es mi código de dibujo para dibujar una línea personalizada con el mouse sobre un Gráfico. ¿Puedes ayudarme a hacerlo de la manera adecuada?¿Cuál es la forma correcta de trazar una línea con el mouse en C#

namespace Grafi 
    { 
     public partial class Form1 : Form 
     { 

      bool isDrawing = false; 
      Point prevPoint; 

      public Form1() 
      { 
       InitializeComponent(); 
      } 

      private void chartTemperature_MouseDown(object sender, MouseEventArgs e) 
      { 
       isDrawing = true; 
       prevPoint = e.Location; 
      } 

      private void chartTemperature_MouseMove(object sender, MouseEventArgs e) 
      { 
       Pen p = new Pen(Color.Red, 2); 
       if (isDrawing) 
       { 
        Graphics g = chartTemperature.CreateGraphics();  
        g.DrawLine(p, prevPoint, e.Location); 
        prevPoint = e.Location; 

        numOfMouseEvents = 0;    
       } 
       p.Dispose(); 
      } 

      private void chartTemperature_MouseUp(object sender, MouseEventArgs e) 
      { 
       isDrawing = false; 
      } 
     } 
    } 

El problema es que cuando cambio el tamaño de mi línea desaparece. Desaparece cada vez que se genera un evento onPaint.

+1

¿Puede explicar qué quiere decir con * properly *? En el caso * any *, tendrá que manejar los eventos 'Mouse Up/Down/Move'. –

+0

Para aclarar, esta pregunta es en respuesta a un problema planteado al responder a una pregunta anterior: http://stackoverflow.com/questions/4164190/how-to-save-graphics-object-as-image-in-c/4164625 # 4164625. Él quiere saber la mejor manera de modificar el código existente para dibujar en el evento 'Paint', en lugar de usar' CreateGraphics'. –

+0

Hay varias buenas muestras de muestras de pintura en CodeProject. Van desde lo más simple a lo bastante complejo. Verifica algunos de ellos. Verá las diferentes maneras en que puede hacer esto correctamente, aunque todos los métodos implicarán guardar los puntos de movimiento del mouse en una colección y volver a dibujarlos en un controlador de eventos paint. –

Respuesta

7

Pruebe esto ... Se trata de un método de trazo, implementado de forma muy simple y lo más cerca posible de su propio código.Stokes son colecciones individuales de movimientos del mouse. Cada movimiento del mouse entre abajo y arriba se registra como un trazo, todos los trazos se recopilan y luego se vuelven a dibujar cada vez que se dispara el evento de pintura. Este ejemplo es simple pero podría ser un buen punto de partida.

Tenga en cuenta que deberá agregar el controlador de pintura para su objeto de gráfico.

using System; 
using System.Collections.Generic; 
using System.Drawing; 
using System.Windows.Forms; 
using System.Drawing.Drawing2D; 

namespace Grafi 
{ 
    public partial class Form1 : Form 
    { 
     bool isDrawing; 
     // our collection of strokes for drawing 
     List<List<Point>> _strokes = new List<List<Point>>(); 
     // the current stroke being drawn 
     List<Point> _currStroke; 
     // our pen 
     Pen _pen = new Pen(Color.Red, 2); 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void chartTemperature_MouseDown(object sender, MouseEventArgs e) 
     { 
      isDrawing = true; 
      // mouse is down, starting new stroke 
      _currStroke = new List<Point>(); 
      // add the initial point to the new stroke 
      _currStroke.Add(e.Location); 
      // add the new stroke collection to our strokes collection 
      _strokes.Add(_currStroke); 
     } 

     private void chartTemperature_MouseMove(object sender, MouseEventArgs e) 
     { 
      if (isDrawing) 
      { 
       // record stroke point if we're in drawing mode 
       _currStroke.Add(e.Location); 
       Refresh(); // refresh the drawing to see the latest section 
      } 
     } 

     private void chartTemperature_MouseUp(object sender, MouseEventArgs e) 
     { 
      isDrawing = false; 
     } 

     private void chartTemperature_Paint(object sender, PaintEventArgs e) 
     { 
      // now handle and redraw our strokes on the paint event 
      e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; 
      foreach (List<Point> stroke in _strokes.Where(x => x.Count > 1)) 
       e.Graphics.DrawLines(_pen, stroke.ToArray()); 
     } 
    } 
} 
+0

Gracias. (pocos caracteres más tontos) – Primoz

+0

Intenté su método, funciona pero mi panel "parpadea" cuando estoy dibujando. Probablemente se deba a las llamadas de refresco continuas (yo uso el método de invalidación (falso)). ¿Conoces alguna solución? – Nick

+1

@Nick: Sí, lo hay. Esta es realmente una pregunta aparte, pero debes establecer la propiedad DoubleBuffered de tu control en verdadero. El doble almacenamiento en memoria intermedia previene el parpadeo. Vea aquí: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.doublebuffered(v=vs.110).aspx Sin embargo, una nota de precaución: la última vez que hice alguna acción personalizada el dibujo fue con .NET 2.0. En esa versión, configurar la propiedad DoubleBuffer no fue tan sencillo para ciertos controles. Form.DoubleBuffered era fácil, pero algunos controles requerían una llamada diferente, así que ten cuidado con eso. –

0

Hace un tiempo publiqué un solution sobre cómo dibujar una línea con los movimientos del mouse. Esto debería funcionar para ti.

Point mAnchorPoint = new Point(200, 200); 
    Point mPreviousPoint = Point.Empty; 

    private void panel1_MouseMove(object sender, MouseEventArgs e) 
    { 
    if (mPreviousPoint != Point.Empty) 
    { 
     // Clear last line drawn 
     ControlPaint.DrawReversibleLine(PointToScreen(mAnchorPoint), PointToScreen(mPreviousPoint), Color.Pink); 
    } 

    // Update previous point 
    mPreviousPoint = e.Location; 
    mPreviousPoint.Offset(myPanel1.Location); 

    // Draw the new line 
    ControlPaint.DrawReversibleLine(PointToScreen(mAnchorPoint), PointToScreen(mPreviousPoint), Color.Pink); 
    } 

Básicamente lo que puede hacer es trazar una línea cada vez que se mueve el mouse. Si había una línea anterior y todavía está moviendo el mouse, borre la línea y dibuje la nueva. Tenga en cuenta que este ejemplo se compensa basándose en un Panel específico (myPanel1 en este ejemplo). Ajustar en consecuencia. Si cambia el tamaño del control, tendrá que volver a dibujar la línea utilizando el punto anterior del punto de anclaje.

+0

-1 Por favor, publique un fragmento del código y una breve explicación junto con su enlace. Responde a @CRoss y voy a +1. –

+0

@CRoss - Actualizado. Avíseme si desea más detalles. – SwDevMan81

1

¿Tiene algún problema con su implementación actual? ¿Funciona, o solo desea mejorar el código para una función que ya funciona?

Creo que la lógica se ve bien. Sin embargo, me gustaría añadir una cláusula mediante la pluma de la siguiente manera:

private void chartTemperature_MouseMove(object sender, MouseEventArgs e) 
{ 
    using(Pen p = new Pen(Color.Red, 2)){ 
    if (isDrawing) 
    { 
     Graphics g = chartTemperature.CreateGraphics();  
     g.DrawLine(p, prevPoint, e.Location); 
     prevPoint = e.Location; 

     numOfMouseEvents = 0;    
    } 
    } 
} 

De esta manera su pluma se dispondrá incluso en el caso de las excepciones que ocurren después de su creación y su llamada a Dispose.

Sin embargo, también puede pensar en hacer de la Pen una variable de clase para que no tenga que crearla y deshacerse de ella cada vez que mueva el mouse.

+0

El problema es que cuando cambio el tamaño de mi línea desaparece. Desaparece cada vez que se genera un evento onPaint. – Primoz

+0

@Primoz - Eso es porque no almacena los puntos en todas partes. Haga una colección de StartPoints y EndPoints, y en MouseUp agregue el punto de inicio actual y el punto final a las colecciones. A continuación, anule el evento OnPaint y, cuando se vuelva a pintar la ventana, recorra la colección y pinte las líneas con el objeto gráfico del gráfico. –

1

Necesita almacenar su línea en algún lugar.

Los pasos que debe tomar son:

  1. Crear un lugar para almacenar sus puntos en la clase principal, por ejemplo. un ArrayList<ArrayList<Point>> - donde cada ArrayList<Point> contiene la lista de puntos en una línea.
  2. espera para eventos MouseDown y crear una matriz para una nueva línea (por ejemplo, un new ArrayList<Point>) al final de la lista de líneas
  3. espera para eventos mouseMoved, y añadir un punto a la última línea de la lista, siempre que sea el mouse es arrastrado pregunta para actualizar tu ventana aquí.
  4. en su paint, recorra todas las líneas y dibuje cada punto de cada línea en la matriz.
  5. para borrar el dibujo, simplemente reemplace la matriz con una lista en blanco y actualice la ventana.

Si no almacena sus líneas en algún lugar, se perderán. ¿Esto tiene sentido?

La otra forma de almacenar líneas es mediante el uso de un objeto Canvas, donde el mapa de píxeles de lo dibujado se recuerda y se dibuja automáticamente. Si no te importa no tener los datos de tu línea como puntos vectoriales, y es posible que también quieras usar imágenes o colores, este podría ser un mejor enfoque.

Cuestiones relacionadas