2

I have a Windows Forms application in C# with drawing panel and a button - for drawing a line.

When you click the button, you can draw a line for 2 random points.

Pen p = new Pen(Color.Black, 5);
//point for start 
Point ps = new Point();
//point for end 
Point pe = new Point();

private void drawPanel_MouseDown(object sender, MouseEventArgs e)
{
  ps.X = e.X;
  ps.Y = e.Y;
  pe = ps;
}

private void drawPanel_MouseMove(object sender, MouseEventArgs e)
{
  // when button is clicked for drawing draw = true;
  if (draw)
  {
    if (e.Button == MouseButtons.Left)
    { 
      pe = new Point(e.X, e.Y);
    }
  }
}

private void drawPanel_MouseUp(object sender, MouseEventArgs e)
{
  onMouseUpFlag = true;
}

private void drawPanel_Paint(object sender, PaintEventArgs e)
{
  Graphics g = drawPanel.CreateGraphics();
  if (onMouseUpFlag)
  {
    g.DrawLine(p, ps, pe); 
    g.Dispose(); 
  }
} 

The program has some flaws :

  • When you draw a line it shows it, only if the main window is moved somewhere(usually when I hide it)
  • It can draw only 1 line.

Any suggestions how to fix these bugs ?

EDIT

I've read you answers and made some changes :

Pen p = new Pen(Color.Black, 5); 
Point ps = new Point();
Point pe = new Point();

List<Point> linesStart= new List<Point>();
List<Point> linesEnd= new List<Point>();

private void drawPanel_MouseDown(object sender, MouseEventArgs e)
{
  ps.X = e.X;
  ps.Y = e.Y;

  linesStart.Add(ps);

  pe = ps;
}

private void drawPanel_MouseMove(object sender, MouseEventArgs e)
{
  if (e.Button == MouseButtons.Left)
  {
    pe = new Point(e.X, e.Y);

    //adding end point .. actually adds a lot of points 
    linesEnd.Add(pe);
  }
}

bool onMouseUpFlag = false;

private void drawPanel_MouseUp(object sender, MouseEventArgs e)
{
  onMouseUpFlag = true;
  drawPanel.Invalidate();
}

private void drawPanel_Paint(object sender, PaintEventArgs e)
{ 
  if (onMouseUpFlag)
  {
    for (int i = 0; i < linesStart.Count; i++)
    {
      e.Graphics.DrawLine(p, linesStart[i], linesEnd[i]);
    } 
  }
} 

Now I'm trying to fix the DrawLine for multiple lines. Paint event can do multiple line but only the starting point is fine. Somehow the end point is not very correct. Where I can set exactly the last point of the MouseMove event ?

LarsTech
  • 80,625
  • 14
  • 153
  • 225
Bor
  • 775
  • 3
  • 19
  • 44
  • I updated my answer. Please try to avoid changing the question. If you have more questions, feel free to post it as a separate question. – LarsTech Oct 30 '12 at 16:17

3 Answers3

3

You have to call the Invalidate method on the panel:

private void drawPanel_MouseUp(object sender, MouseEventArgs e)
{
  onMouseUpFlag = true;
  drawPanel.Invalidate();
}

Also, use the Graphic object from the PaintEvent:

private void drawPanel_Paint(object sender, PaintEventArgs e)
{
  if (onMouseUpFlag)
  {
    e.Graphics.DrawLine(p, ps, pe); 
  }
} 

For multiple lines, you would have to hold the points in a collection object.

Per your updated code, here is a working example of what I think you are trying to do:

private class Line {
  public Point Starting { get; set; }
  public Point Ending { get; set; }

  public Line(Point starting, Point ending) {
    this.Starting = starting;
    this.Ending = ending;
  }
}
List<Line> lines = new List<Line>();

private Point downPoint = Point.Empty;
private Point movePoint = Point.Empty;
private bool movingLine = false;

public Form1() {
  InitializeComponent();

  panel1.Paint += panel1_Paint;
  panel1.MouseDown += panel1_MouseDown;
  panel1.MouseMove += panel1_MouseMove;
  panel1.MouseUp += panel1_MouseUp;
}

void panel1_MouseDown(object sender, MouseEventArgs e) {
  if (e.Button == MouseButtons.Left) {
    downPoint = e.Location;
  }
}

void panel1_MouseMove(object sender, MouseEventArgs e) {
  if (e.Button == MouseButtons.Left) {
    movingLine = true;
    movePoint = e.Location;
    panel1.Invalidate();
  }
}

void panel1_MouseUp(object sender, MouseEventArgs e) {
  if (e.Button == MouseButtons.Left) {
    movingLine = false;
    lines.Add(new Line(downPoint, e.Location));
    panel1.Invalidate();
  }
}

void panel1_Paint(object sender, PaintEventArgs e) {
  e.Graphics.Clear(Color.White);
  foreach (Line l in lines) {
    e.Graphics.DrawLine(Pens.Black, l.Starting, l.Ending);
  }

  if (movingLine) {
    e.Graphics.DrawLine(Pens.Black, downPoint, movePoint);
  }

}

Use an inherited panel to turn on the DoubleBuffer property to avoid flickering.

Community
  • 1
  • 1
LarsTech
  • 80,625
  • 14
  • 153
  • 225
1

Whenever you want to redraw (in your code) you should call panelinvalidate drawPanel.Invalidate().

When you finish mouse moving and release the button

private void drawPanel_MouseUp(object sender, MouseEventArgs e)
{
            onMouseUpFlag = true;
            drawPanel.Invalidate();
}

And at the end I would suggest to use this code in your drawPanel_Paint instead of that of yours . You should use Graphics provided by an EventArgs, not create new one.

private void drawPanel_Paint(object sender, PaintEventArgs e)
{
            if (onMouseUpFlag)
            {
                  e.Graphics.DrawLine(p, ps, pe); 
            }
}
Nikola Davidovic
  • 8,556
  • 1
  • 27
  • 33
1
  1. You need to trigger a repaint event after the mouse is let go. Just call drawPanel.Invalidate() to cause the form to be redrawn.

  2. To draw multiple lines, you'll have to store the information for each one in a list or something, and draw each line in your repaint. The Paint method basically starts with a blank space each time, so it will only draw the most recent the way you currently have it set up.

Tyler Lee
  • 2,736
  • 13
  • 24