2010-10-30 7 views
8

Non sono abbastanza sicuro come disegnare un rettangolo (non riempito) quando trascino il mio mouse mentre si fa clic con il tasto sinistro del mouse.Come disegnare il rettangolo su MouseDown/Sposta C#

ho questo finora

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

Ma i problemi che io non voglio tutti i rettangoli di presentarsi

risposta

19

Alcuni codice di andare con risposta corretta di 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()); 
    } 

per ottenere un 'canevas' che ha il doppio buffer accesi , quindi la pittura non sfarfallio, utilizzare Progetto + Aggiungi nuovo elemento, selezionare "Classe" e incollare questo codice:

using System; 
using System.Windows.Forms; 

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

Compila. Trascina il nuovo controllo dalla parte superiore della casella degli strumenti sul modulo, sostituendo i "canevas" originali. Aggiorna di conseguenza i gestori di eventi.

+1

grazie, l'ho avuto correttamente ma mi ha aiutato con il trascinamento ripristinato. :) – Burnzy

+0

Tutto sembra ok finora, tranne lo sfarfallio, qualche idea? – Burnzy

+0

Ho lasciato un commento, stai usando e.Graphics nell'evento Paint? Ho testato questo codice, è privo di sfarfallio anche senza doppio buffer. –

5

Non chiamare CreateGraphics. In MouseDown, memorizza la posizione iniziale e una bandiera per indicare che stai disegnando. In MouseMove, controlla il flag. Se stai disegnando, crea il rettangolo relativo alla posizione iniziale e memorizzalo (cosa che stai già facendo), quindi chiama Invalidate(). Tutto il tuo codice di disegno sarà in OnPaint() (canvas.Paint dall'esterno della classe, anche se probabilmente dovrei creare la mia classe per evitare di sporcare il codice del modulo con questa roba).

Il disegno deve essere eseguito nel gestore vernice (OnPaint). Se si disegna al di fuori di questo, l'oggetto grafico non viene cancellato (quindi i rettangoli multipli) e tutto ciò che si disegna ad esso può/verrà cancellato in momenti apparentemente strani quando la finestra riceve un messaggio WM_PAINT.

EDIT: Ora che si verificano problemi di prestazioni, ci sono un paio di semplici modi per ottimizzare un po 'la verniciatura. Innanzitutto, Invalidate sceglierà opzionalmente un rettangolo in modo che non sia necessario ridisegnare l'intero controllo. In secondo luogo, se stai disegnando su MouseMove stai per disegnare un bel po '. Anche l'utilizzo del doppio buffering aiuterà molto, basta impostare la proprietà DoubleBuffered su true o aggiungerla al valore di ControlStyles chiamando SetStyle sul controllo.

+0

btw, non sono sicuro di cosa sia valido per – Burnzy

+0

@Burnzy, Invalidate convalida la grafica del controllo in modo che l'operazione di disegno venga richiamata nuovamente da Windows. (Fondamentalmente una volta che il controllo è stato invalidato, è necessario ridisegnarlo) –

+0

qualche idea su come risolvere il problema dello sfarfallio? – Burnzy

0

Bene, ora ho questo, funziona ma, sfarfallio, anche con doppio buffering.

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

E poi sulla vernice

  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

* Non * utilizzare CreateGraphics(). Usa e.Graphics nell'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; 
    } 

Aggiungi questo codice al modulo. Questo potrebbe ridurre lo sfarfallio!