2010-04-09 16 views
9

Bir çizim programı üzerinde çalışıyorum ancak bir lastik bant çizgisi çizerken bir fare imlecini hareket ettirirken titreme ile ilgili bir sorun yaşıyorum. Kesinlikle zorunda kalmadıkçaC# grafikleri titriyor

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

Formlarınız veya denetimlerinizde çift arabelleğe alınıyor mu? – FrustratedWithFormsDesigner

+3

Bu yardımcı olmadı. – Jeff

cevap

23

İlk CreateGraphics() kullanmayın: Sana hattın o titremeyi engellemek için bana yardımcı olabilir umut, burada kodudur. Bir olay işleyiciyi OnPaint'a bağlayın ve yüzeyi yenilemek istediğinizde Invalidate() numaralı telefonu arayın.

Titremesini istemiyorsanız çizim yüzeyinizi iki kez tamponlamanız gerekir. Bunu yapmanın en kolay yolu, formunuzun DoubleBuffered özelliğini True olarak belirlemektir.

Çiziminizi PictureBox denetimine genişletmek için bunu genişletmeyi planlıyorsanız önemle tavsiye ederim. PictureBox varsayılan olarak çift tamponludur ve çizim bölgenizi çok daha basit bir şekilde kontrol etmenizi sağlar. kodunda

:

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

Düzenleme:

diğer konu, özel bir Pen üyesini yaratıyor. Kalemler (ve Fırçalar, ayrıca birçok GDI + nesnesi), düzenlenmesi gereken, yönetilmeyen nesneler için kolları temsil eder, aksi takdirde programınız sızacaktır. Bunları using ifadelerine (tercih edilen ve istisnai olarak güvenli bir şekilde) sarın veya bunları formun Dispose yöntemine açıkça atın.

System.Drawing'de alternatif olarak, önceden oluşturulmamış Kalemler ve Fırçalar'a erişmeniz (ve verilmemeniz) gerekenlere erişebilirsiniz. Onları gibi kullanın:

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

Cevabınız ve öneriniz için teşekkürler, düzeltmeye çalışacağım. – Jeff

+0

Koduyla küçük bir sorunu çözdüm, xG nesnesinden kurtularak formun grafik içeriğini almak için Paint etkinliğindeki PaintEventArgs öğesinin "e.Graphics" özelliğini kullanabilirsiniz. –

+0

Evet, işe yarıyor. Çok teşekkürler. Şimdi de Invalidate() kullanımını anlıyorum. Güzel. – Jeff

6

o titreyen bir nedeni (hemen ekranda görüntülenir çizgiyi silerek), arka planı çizimi ve daha sonra çizgiyi üst üste olmasıdır. Böylelikle çizgi kayboluyor ve beliriyor, titrek bir görüntü veriyor.

Buna en iyi çözüm, Double Buffering olarak adlandırılır. Yaptığınız şey, tüm görüntüyü "kapalı" bir bitmap'e çizmektir ve yalnızca tamamlandığında ekranda göstermektir. Tamamlanmış görüntüyü sadece görüntülediğiniz için, titreşen bir etki olmaz. WinForms'un sizin için tüm zor işleri yapmasını sağlamak için this.DoubleBuffered = true değerini ayarlayabilmeniz gerekir.

NB: Boya işleyicinizin dışına çizim yapmamanız gerekir - ideal olarak, yeniden çizilmesi gereken alanı Invalidate() yapmalısınız ve ardından boya işleyiciniz bu alanı yeniden çizecektir (gerektiği gibi herhangi bir taşma çizgisiyle)).

+0

Detaylı açıklama için teşekkür ederiz – Jeff

2

Sabit ve çalışma kodu.

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

Bu benim çözümümü değiştirdi ve benim fare hareket olay çalışmayı durdurdu, lol – Pavel