2010-04-09 4 views
9

Pracuję nad rodzajem programu do rysowania, ale mam problem z migotaniem podczas przesuwania kursora myszy podczas rysowania linii gumki. Mam nadzieję, że może mi pomóc, aby usunąć ten migotanie linii, oto kod:Migotanie grafiki C#

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

Czy w formularzach lub kontrolkach występuje podwójne buforowanie? – FrustratedWithFormsDesigner

+3

To nie pomogło. – Jeff

Odpowiedz

23

pierwsze nie używaj CreateGraphics() chyba że koniecznie musisz. Przypisz obsługę zdarzeń do OnPaint i zadzwoń pod numer Invalidate(), gdy chcesz odświeżyć powierzchnię.

Jeśli nie chcesz, aby migotało, musisz podwoić bufor swojej powierzchni rysunkowej. Najprostszym sposobem jest ustawienie właściwości formularza na DoubleBuffered na wartość True.

Gorąco polecam, jeśli planujesz rozszerzyć to, aby wykonać rysunek do sterowania PictureBox. PictureBox jest domyślnie podwójnie buforowany i pozwala ci łatwiej kontrolować region rysowania.

W kodzie:

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

Edit:

Kolejną kwestią, tworzysz prywatną Pen członka. Długopisy (i pędzle, a także wiele obiektów GDI +) reprezentują uchwyty dla niezarządzanych obiektów, które należy usunąć, w przeciwnym razie program wycieknie. Zapakuj je w instrukcje (preferowane i wyjątkowe) lub jawnie pozbądź się ich w formie Dispose.

Alternatywnie w System.Drawing można uzyskać dostęp do niektórych gotowych pisaków i pędzli, które nie muszą być (i nie powinny być) usuwane. Wykorzystywać je jak:

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

Dzięki za odpowiedź i za sugestię, spróbuję to naprawić. – Jeff

+0

Naprawiłem mały problem z kodem, możesz pozbyć się swojego obiektu xG i użyć właściwości 'e.Graphics' PaintEventArgs w zdarzeniu paint, aby uzyskać kontekst graficzny swojego formularza. –

+0

Tak, to działa. Wielkie dzięki. Teraz rozumiem również użycie Invalidate(). Miły. – Jeff

6

Powodem jest to, że migotanie rysowania tła (który jest natychmiast wyświetlany na ekranie, ocierając linię), a następnie nałożyć linię. W ten sposób linia znika i pojawia się, dając migotliwy wyświetlacz.

Najlepszym rozwiązaniem tego problemu jest podwójne buforowanie. To, co robisz, polega na narysowaniu całego obrazu na bitmapie "poza ekranem" i wyświetleniu go na ekranie po zakończeniu. Ponieważ wyświetlasz tylko gotowy obraz, nie ma efektu migotania. Powinieneś być w stanie ustawić To.DoubleBuffered = true, aby uzyskać WinForms zrobić całą ciężką pracę dla ciebie.

NB: Nie powinieneś w ogóle rysować na zewnątrz lakieru - najlepiej, jeśli powinieneś unieruchomić() obszar, który wymaga przerysowania, a następnie twój lakiernik przerysuje tylko ten obszar (w razie potrzeby z nałożonymi liniami itp.).

+0

Dziękuję za szczegółowe wyjaśnienie – Jeff

2

Naprawiony i działający kod.

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

Zmieniono moje rozwiązanie na to i moje ruchy myszy przestały działać, lol – Pavel