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 = eX; yFirst = eY; draw = true; } private void Form1_MouseUp(object sender, MouseEventArgs e) { bmG.DrawLine(pen, xFirst, yFirst, eX, eY); 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, eX, eY); } } private void Form1_Paint(object sender, PaintEventArgs e) { xG.DrawImage(bm, 0, 0); } } } 

首先不要使用CreateGraphics()除非你绝对必须这样做。 将事件处理程序绑定到OnPaint并在要刷新表面时调用Invalidate()

如果你不想让它闪烁,你需要双倍缓冲你的绘图表面。 最简单的方法是将表单的DoubleBuffered属性设置为True。

如果你打算扩展它来绘制PictureBox控件,我强烈建议你。 PictureBox默认为双缓冲,允许您更简单地控制绘图区域。

在代码中:

 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 = eX; yFirst = eY; draw = true; } private void Form1_MouseUp(object sender, MouseEventArgs e) { bmG.DrawLine(pen, xFirst, yFirst, eX, eY); 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, eX, eY); } else { e.Graphics.DrawImage(bm, 0, 0); } } } 

编辑:

另一个问题是,您正在创建一个私有的Pen成员。 笔(和Brushes,以及许多GDI +对象)表示需要处理的非托管对象的句柄,否则您的程序将泄漏。 要么using语句(首选和exception安全的方式)将它们包装起来,要么在表单的Dispose方法中明确地处理它们。

或者在System.Drawing中,您可以访问一些不需要(也不应该)处置的预构建的笔和画笔。 使用它们像:

  private void Form1_Paint(object sender, PaintEventArgs e) { if (draw) { e.Graphics.DrawImage(bm, 0, 0); e.Graphics.DrawLine(Pens.Black, xFirst, yFirst, eX, eY); } else { e.Graphics.DrawImage(bm, 0, 0); } } 

它闪烁的原因是你正在绘制背景(立即显示在屏幕上,擦掉线条),然后叠加线条。 因此,线条不断消失并出现,呈现闪烁的显示。

对此最好的解决方案称为双缓冲。 您所做的是将整个图像绘制到“屏幕外”位图,并在完成时仅在屏幕上显示。 因为您只显示完成的图像,所以没有闪烁效果。 您应该能够设置this.DoubleBuffered = true以使WinForms为您完成所有艰苦的工作。

注意:您不应该在绘图处理程序之外绘图 – 理想情况下,您应该对需要重绘的区域进行Invalidate(),然后您的绘制处理程序将重新绘制该区域(根据需要重叠任何线条等)。

固定和工作代码。

 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 = eX; y1 = eY; } private void pictureBox_MouseUp(object sender, MouseEventArgs e) { drag = false; bmg.DrawLine(Pens.Black, x1, y1, eX, eY); pictureBox.Invalidate(); } private void pictureBox_MouseMove(object sender, MouseEventArgs e) { if (drag) { x2 = eX; y2 = eY; 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); } } }