2010-04-09 3 views
9

Я работаю над программой рисования, но у меня есть проблема с мерцанием при перемещении курсора мыши при рисовании линии резинкой. Я надеюсь, что вы можете мне помочь, чтобы удалить эту мерцание строки, вот код: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

Является ли двойной буфер в ваших формах или элементах управления? – FrustratedWithFormsDesigner

+3

Это не помогло. – Jeff

ответ

23

Во-первых, не используйте 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 = 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:

Другой вопрос, вы создаете частный Pen элемент. Ручки (и кисти, а также многие объекты GDI +) представляют собой ручки неуправляемых объектов, которые нужно удалять, иначе ваша программа будет протекать. Либо оберните их в операторы using (предпочтительный и безопасный путь), либо явно удалите их в методе 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, e.X, e.Y); 
     } else { 
      e.Graphics.DrawImage(bm, 0, 0); 
     } 
    } 
+0

Спасибо за ответ и за предложение, я постараюсь это исправить. – Jeff

+0

Я исправил небольшую проблему с кодом, вы можете избавиться от объекта xG и использовать свойство «e.Graphics» в PaintEventArgs в событии рисования, чтобы получить графический контекст вашей формы. –

+0

Да, это работает. Большое спасибо. Теперь я понимаю использование Invalidate(). Ницца. – Jeff

6

Причина, по которой мерцает является то, что вы рисуете фон (который сразу же отображается на экране, стирая линию), а затем наложите линию. Таким образом, линия продолжает исчезать и появляться, давая мерцающий дисплей.

Лучшее решение для этого называется двойной буферизацией. То, что вы делаете, это рисовать все изображение на «внеэкранном» растровом изображении и показывать его только на экране, когда оно будет завершено. Поскольку вы только показываете завершенное изображение, нет мерцающего эффекта. Вы должны просто установить этот.DoubleBuffered = true, чтобы заставить WinForms выполнять всю тяжелую работу для вас.

NB: Вы не должны рисовать за пределами обработчика краски - в идеале вы должны Invalidate() область, которая нуждается в перерисовке, а затем ваш обработчик краски будет перерисовывать именно эту область (с любыми наложенными линиями и т. Д. По мере необходимости).

+0

Благодарим вас за подробное объяснение – Jeff

2

Исправлен и работает код.

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

Изменено мое решение для этого и моего перемещения мыши событие перестало работать, LOL – Pavel

Смежные вопросы