2010-11-12 14 views
8

Questo è il mio codice di disegno per disegnare una linea personalizzata con il mouse su un grafico. Potete per favore aiutarmi a farlo nel modo giusto?Qual è il modo corretto di disegnare una linea con il mouse in 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; 
      } 
     } 
    } 

Il problema è che quando ridimensiono il modulo la mia riga scompare. Scompare ogni volta che viene generato un evento onPaint.

+1

Puoi spiegare, cosa intendi esattamente con * correttamente *? In * qualsiasi * caso, dovrai gestire gli eventi 'Mouse su/giù/sposta '. –

+0

Per chiarimenti, questa domanda è in risposta a un problema sollevato nel rispondere a una domanda precedente: http://stackoverflow.com/questions/4164190/how-to-save-graphics-object-as-image-in-c/4164625 # 4.164.625. Vuole sapere il modo migliore per modificare il codice esistente per disegnare nell'evento 'Paint', invece di usare' CreateGraphics'. –

+0

Esistono vari esempi di esempi di pittura su CodeProject. Si va dal molto semplice al piuttosto complesso. Controlla alcuni di loro. Vedrai i diversi modi in cui puoi farlo correttamente, sebbene tutti i metodi implichino il salvataggio dei punti di spostamento del mouse in una raccolta e il loro ridisegno in un gestore di eventi paint. –

risposta

7

Prova questo ... È un metodo di disegno a tratti, implementato in modo molto semplice e il più vicino possibile al tuo codice.Gli Stokes sono raccolte individuali di movimenti del mouse. Ogni mossa del mouse tra il basso e l'alto viene registrata come un tratto, tutti i tratti vengono raccolti e quindi ridisegnati ogni volta che viene attivato l'evento paint. Questo esempio è semplice ma potrebbe essere un buon punto di partenza.

Si noti che sarà necessario aggiungere il gestore di vernice per l'oggetto grafico.

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

Grazie. (pochi caratteri più stupidi) – Primoz

+0

Ho provato il tuo metodo, funziona ma il mio pannello "lampeggia" quando disegno. Probabilmente è dovuto alle chiamate di aggiornamento continuo (utilizzo il metodo Invalidate (false)). Conosci qualche soluzione? – Nick

+1

@Nick: Sì, c'è. Questa è una domanda a parte, ma è necessario impostare la proprietà DoubleBuffered del controllo su true. Il buffering doppio impedisce lo sfarfallio. Vedi qui: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.doublebuffered(v=vs.110).aspx Una nota di cautela però: l'ultima volta che ho fatto qualche custom il disegno era con .NET 2.0. In quella versione l'impostazione della proprietà DoubleBuffer non era così semplice per determinati controlli. Form.DoubleBuffered era facile ma alcuni controlli richiedevano una chiamata diversa, quindi fai attenzione. –

0

Ho postato un solution un po 'indietro su come disegnare una linea usando i movimenti del mouse. Questo dovrebbe funzionare per te.

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

Fondamentalmente ciò che si può fare è tracciare una linea ogni volta che si muove il mouse. Se c'era una linea precedente e stai ancora muovendo il mouse, cancella la linea e disegna quella nuova. Notare che questo offset di esempio si basa su uno specifico Panel (myPanel1 in questo esempio). Regolare di conseguenza. Se ridimensioni il controllo, dovrai ridisegnare la linea usando il punto precedente del punto di ancoraggio.

+0

-1 Si prega di postare alcuni frammenti del codice e una breve spiegazione insieme al tuo link. Rispondi a @CRoss e io farò +1. –

+0

@CRoss - Aggiornato. Fammi sapere se desideri maggiori dettagli. – SwDevMan81

1

Avete problemi con la vostra attuale implementazione? Funziona o vuoi semplicemente rendere il codice migliore per una funzione già funzionante.

Penso che la logica sia a posto. Tuttavia, vorrei aggiungere una clausola con la penna in questo modo:

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

In questo modo la penna sarà disposto anche in caso di eventuali eccezioni che si verificano dopo la sua creazione e la chiamata a Dispose.

Tuttavia, è anche possibile pensare di creare una variabile di classe Pen in modo da non dover creare e disporne ogni volta che si sposta il mouse.

+0

Il problema è che quando ridimensiono il modulo la mia linea scompare. Si disattiva quando viene generato l'evento onPaint. – Primoz

+0

@Primoz: perché non si memorizzano i punti ovunque. Crea una raccolta di StartPoints e EndPoint e su MouseUp aggiungi il punto di partenza corrente e l'endpoint alle raccolte. Quindi eseguire l'override dell'evento OnPaint e, quando la finestra viene ridipinta, scorrere la raccolta e dipingere le linee utilizzando l'oggetto grafico del grafico. –

1

È necessario memorizzare la linea da qualche parte.

I passi che dovete prendere sono:

  1. Creare un posto per memorizzare i punti nella classe principale, per es. un ArrayList<ArrayList<Point>> - dove ogni ArrayList<Point> contiene l'elenco di punti in una riga.
  2. attesa per eventi MouseDown, e creare una matrice per una nuova linea (ad esempio un new ArrayList<Point>) alla fine dell'elenco delle linee
  3. attesa per gli eventi mousemoved, e aggiungere un punto per l'ultima riga nella lista, ogni volta il mouse viene trascinato. chiedi di aggiornare la tua finestra qui.
  4. nel tuo paint, scorrere tutte le linee e disegnare ogni punto di ogni linea nell'array.
  5. per cancellare il disegno, è sufficiente sostituire l'array con una lista vuota e aggiornare la finestra.

Se non si memorizzano le linee da qualche parte, saranno perse. Ha senso ciò?

L'altro modo di memorizzare le righe è utilizzando un oggetto Canvas, in cui la mappa dei pixel di ciò che viene disegnato viene memorizzata e disegnata automaticamente. Se non ti dispiace non avere i tuoi dati di linea come punti vettoriali, e potresti anche voler usare immagini o colori, allora questo potrebbe essere un approccio migliore.