I want to draw a line by mouse(interactively) , I used C# and WinForm, the line should appear at any time from the starting point(when the mouse press on the panel) to the current position of the mouse, exactly like drawing a line in Paint program.
but the code produces a lot of lines, i know why but i don't know how to overcome this problem
Here is my code:
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Graphics g;
Pen myPen = new Pen(Color.Red);
Point p = new Point();
bool flag = false;
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
flag = true;
p = e.Location;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (flag)
{
g = panel1.CreateGraphics();
myPen.Width = 3;
Point p2 = new Point();
p2 = e.Location;
g.DrawLine(myPen, p, p2);
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
flag = false;
}
}}
Any Help? i want to draw many lines and keep the code simple as possible!
You will need to better manage the drawing. Some pointers:
- Don't use
CreateGraphics
. Instead, use the Paint
event already provided by the control.
- Do your drawing in an inherited class of your own. Don't draw in the
Form
class unless you're drawing on the form.
Here's an example class. It's inherited from Panel
. Simply add this to a form, such as in the Form's constructor using something like this.Controls.Add(new PanelWithMouseDraw());
.
Note: this uses Tuple
which I believe requires .NET 4.0 or above. You could replace this structure with something else, if need be...you just need to keep a list of Point
pairs.
namespace WindowsFormsApplication1
{
public class PanelWithMouseDraw : Panel
{
private Point _origin = Point.Empty;
private Point _terminus = Point.Empty;
private Boolean _draw = false;
private List<Tuple<Point, Point>> _lines = new List<Tuple<Point, Point>>();
public PanelWithMouseDraw()
{
Dock = DockStyle.Fill;
DoubleBuffered = true;
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
_draw = true;
_origin = e.Location;
}
else
{
_draw = false;
_origin = Point.Empty;
}
_terminus = Point.Empty;
Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
if (_draw && !_origin.IsEmpty && !_terminus.IsEmpty)
_lines.Add(new Tuple<Point, Point>(_origin, _terminus));
_draw = false;
_origin = Point.Empty;
_terminus = Point.Empty;
Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.Button == MouseButtons.Left)
_terminus = e.Location;
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
foreach (var line in _lines)
e.Graphics.DrawLine(Pens.Blue, line.Item1, line.Item2);
if (!_origin.IsEmpty && !_terminus.IsEmpty)
e.Graphics.DrawLine(Pens.Red, _origin, _terminus);
}
}
}
Simple fix, change the method panel1_MouseMove
as follows:
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (flag)
{
g = panel1.CreateGraphics();
myPen.Width = 3;
Point p2 = new Point();
p2 = e.Location;
g.DrawLine(myPen, p, p2);
p = p2; // just add this
}
}
Keep in mind this will work with any mouse button down, left or right doesnt matter.
Edit1:
This should draw a straight line and all the previous ones.
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public struct Line
{
public Point start;
public Point end;
}
public Form1()
{
InitializeComponent();
}
Pen erasePen = new Pen(Color.White, 3.0F);
Pen myPen = new Pen(Color.Red, 3.0F);
Point p = new Point();
Point endPoint = new Point();
bool flag = false;
List<WindowsFormsApplication2.Form1.Line> lines = new List<WindowsFormsApplication2.Form1.Line>();
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
flag = true;
p = e.Location;
endPoint = p;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (flag)
{
Graphics g = panel1.CreateGraphics();
Point p2 = e.Location;
EraseLine(p, endPoint, g);
DrawAllLines(lines, g);
DrawLine(p, p2, g);
endPoint = p2;
g.Dispose();
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
// redraw for one last time...
Graphics g = panel1.CreateGraphics();
Point p2 = e.Location;
lines.Add(new Line { start = p, end = p2} );
EraseLine(p, endPoint, g);
DrawAllLines(lines, g);
flag = false;
g.Dispose();
}
private void DrawLine(Point start, Point end, Graphics g)
{
g.DrawLine(myPen, start, end);
}
private void DrawLine(WindowsFormsApplication2.Form1.Line line, Graphics g)
{
g.DrawLine(myPen, line.start, line.end);
}
private void DrawAllLines(List<WindowsFormsApplication2.Form1.Line> allLines, Graphics g)
{
foreach(WindowsFormsApplication2.Form1.Line l in allLines)
{
g.DrawLine(myPen, l.start, l.end);
}
}
private void EraseLine(Point start, Point end, Graphics g)
{
g.DrawLine(erasePen, start, end);
}
}}