Я работаю над видом графического редактора, но у меня есть проблема с мерцанием при перемещении курсора мыши при проведении rubberband линии. Я надеюсь, что можно помочь мне удалить то мерцание строки, вот код:
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);
}
}
}
Во-первых, не используйте 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);
}
}
}
Изменить:
Другая проблема, вы создаете частного члена Pen
. Перья (и кисти, а также многие объекты GDI +) представляют собой дескрипторы неуправляемых объектов, которые необходимо удалить, иначе ваша программа будет протекать. Либо заключите их в , используя операторы
(предпочтительный и безопасный способ), либо явно удалите их с помощью метода формы 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);
}
}
Причина его мерцания в том, что вы рисуете фон (который немедленно отображается на экране, стирая линия), а затем наложите линию. Таким образом, линия продолжает исчезать и появляться, давая мерцающее изображение.
Лучшее решение этой проблемы - двойная буферизация. Что вы делаете, так это рисуете все изображение в растровое изображение «за кадром» и показываете его на экране только после завершения. Поскольку вы всегда показываете только законченное изображение, эффект мерцания отсутствует. Вы должны просто установить this.DoubleBuffered = true, чтобы WinForms выполнял всю тяжелую работу за вас.
NB: на самом деле вам не следует рисовать за пределами обработчика рисования - в идеале вы должны сделать 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 = 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);
}
}
}