Draw, move, and delete line segments in C#

[delete line segments]

This example shows how to make a drawing program that lets you draw, move, and delete line segments. It’s based on the example
Draw and move line segments in C#. See that example for information about how the program lets you draw and move line segments.

This example adds the ability to delete a line segment by dragging it into the trash can. To do that, the program must draw the trash can and detect when you move a segment onto it.

At design time, I added the trash can image (a PNG file with a transparent background) to the program’s resources. (Open the Project menu and select Properties. On the Resources tab, open the Add Resource dropdown and select Add Existing File.) When the program starts, the following code gets the trash can’s dimensions.

// Calculate the trash can dimensions.
private int TrashWidth, TrashHeight;
private void Form1_Load(object sender, EventArgs e)
{
    const float TrashScale = 0.25f;
    TrashWidth = (int)(TrashScale *
        Properties.Resources.trash_empty.Width);
    TrashHeight = (int)(TrashScale *
        Properties.Resources.trash_empty.Height);
}

This code defines the TrashWidth and TrashHeight variables. The form’s Load event handler sets those values to the trash can image’s dimensions multiplied by a scale factor.

The PictureBox object’s Paint event handler draws the current line segments as in the previous example. It then uses the following code to draw the trash can in the upper left corner.

// Draw the trash can.
Rectangle trash_rect = new Rectangle(0, 0,
    TrashWidth, TrashHeight);
e.Graphics.DrawImage(
    Properties.Resources.trash_empty,
    trash_rect);

This code simply creates a rectangle in the upper left corner of the PictureBox that has the desired trash can dimensions. It then calls e.DrawImage to draw the trash can there.

The last and most interesting piece of new code deletes a segment when the user drops it in the trash can.

When you drag a segment to a new location and then release the mouse, the following event handler executes. The new code is shown in blue.

// Stop moving the segment.
private void picCanvas_MouseUp_MovingSegment(
    object sender, MouseEventArgs e)
{
    // Reset the event handlers.
    picCanvas.MouseMove += picCanvas_MouseMove_NotDown;
    picCanvas.MouseMove -= picCanvas_MouseMove_MovingSegment;
    picCanvas.MouseUp -= picCanvas_MouseUp_MovingSegment;

    // See if the mouse is over the trash can.
    if ((e.X >= 0) && (e.X < TrashWidth) &&
        (e.Y >= 0) && (e.Y < TrashHeight))
    {
        if (MessageBox.Show("Delete this segment?",
            "Delete Segment?", MessageBoxButtons.YesNo)
                == DialogResult.Yes)
        {
            // Delete the segment.
            Pt1.RemoveAt(MovingSegment);
            Pt2.RemoveAt(MovingSegment);
        }
    }

    // Redraw.
    picCanvas.Refresh();
}

This code resets the PictureBox event handlers for the situation when the user isn’t dragging anything. The new code then determines whether the mouse is over the trash can. If it is, the program asks the user whether it should delete the line segment. If the user clicks Yes, the program removes the points that define the segment that was dragged.

The method finishes by refreshing the PictureBox to make it redraw the remaining line segments.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in drawing, graphics and tagged , , , , , , , , , , , , , , , , . Bookmark the permalink.

27 Responses to Draw, move, and delete line segments in C#

  1. Pooja Shahane says:

    I want to draw another same line in different color on the same picturebox. but when I try same code with different list of points it will replace first blue lines with red lines.Can you tell me how to draw two different lines on the same picturebox which will be move,stretch and delete

    • RodStephens says:

      If you use the same points, the new line will overdraw the old one. It sounds like maybe you’re using the same points instead of the new ones.

      • Pooja Shahane says:

        I created new list with different points and also I changed all points still it is overdraw the old one…Can you please send source code of drawing two lines??

        • RodStephens says:

          This example uses two lists named Pt1 and Pt2 to hold the end points of the segments. Those are the lines it draws in the Paint event handler.

          You need to either:

          1. Add your new lines to those lists. Then you get new segments in the same color.

          2. Make new similar lists and put the new points in them. Then you can make the Paint event handler draw them in a new color after it draws the first set.

          Do one or the other, not both.

          This example isn’t really intended to be a full-featured editor where you can draw lines with different colors, widths, etc. It’s more to show how you can move segments.

  2. kavin says:

    hi,i need to measure length of the line which are dragged and similarly i need to draw and measure reactangle,circle,arc,ellipse,polygon.can you help me?..
    —thank you in advance–

    • RodStephens says:

      You can calculate the measurements by just finding the distance between the two points. You can multiply by a scale factor if you’re working on a map or some other drawing with a scale.

      For other shapes such as rectangles and ellipses, just change the way the program draws them. For example, instead of calling DrawLine, call DrawRectangle.

      This example may help:

      Let the user draw polygons in C#

      Unfortunately I don’t have time to write the rest of it for you, unless you want to hire me to do it. If you want that, email me.

  3. Taghi Tanasa says:

    Hi , your example is very good.
    Thank you.

  4. Givanildo says:

    Hello Sir Rod Stephens.
    You can provide the draw, move, and delete line segments in C # project in vb.net.
    Thank you for your attention.
    Givanildo

  5. Ravishankar says:

    Hello sir, thanks a lot for this example. It help me a lot,
    but I have one doubt.

    I need to move multiple lines at a time using ISelectable interface. But I am unable to do.can u help me boss

    • RodStephens says:

      First you would need to provide some sort of multi-select. You could use click-and-drag to select segments that intersect the area that you select. You could also use Shift+Click or Ctrl+Click to add and remove items from the selection.

      You would need to change the program so it draws selected objects differently so the user can see which are selected. And it would need to be able to keep selected items even when the mouse is not pressed. Right now the program doesn’t retain the selection when the mouse is up.

      Then when the user clicks and drags starting on a selected item, you would move the whole group.

      All of this is doable but fairly complicated. (I don’t know about the ISelectable interface.)

  6. waqas says:

    its not deleting when i click the trash icon

  7. Pingback: Make a WPF line editor C# - C# HelperC# Helper

  8. SaiNave says:

    Hi Everyone,
    I am working on a GUI program, which plots two different points on an image, using picture box and check box.
    The image first read it on picture box, and then point plots on an image.
    These two different points do not plot at the same time. First point plot when the program started and another point start plotting with the first point when the check box is checked.
    However, when the check box is unchecked the second point stop plotting and only first point do plotting.
    In this case, I need to reset the picture box when the check box is unchecked so that the second point plotting disappear and only first point plot retains and plot with its current value.
    please tell how can I reset the picture box? As I have little knowledge about the GUI programming in C#.
    here the part of my code which I tried :

    namespace WindowsFormsApp11
    {  
        public partial class Form1 : Form
        {
            double x;
            double y;
            Thread T;
            private System.Drawing.Graphics g;
            delegate void update();
            int Flag;
            
           public void Block()
                {
                    StreamReader file1 = new StreamReader(@"C:\Text.txt");
                    string line1;
                    int scale = 100;
    
                    g = pictureBox1.CreateGraphics();
                    Graphics graphic = Graphics.FromImage(pictureBox1.Image);
    
    
                while ((line1 = file1.ReadLine()) != null)
                    {
                        char[] del = new char[] { '\t' };
                        string[] part = line1.Split(del, StringSplitOptions.RemoveEmptyEntries);
    
                        x = Convert.ToDouble(part[0]) * scale;
                        y = Convert.ToDouble(part[1]) * scale;
    
                        g.FillRectangle(Brushes.Red, Convert.ToInt32(x), Convert.ToInt32(y), 10, 10);
                        Thread.Sleep(50);
                        pictureBox1.Invlaidate(); 
                         Update_PicBox();
                   
    
    
                    if (Flag == 1)
                          {
                           g.FillEllipse(Brushes.Blue, Convert.ToInt32(x), Convert.ToInt32(y), 15, 15);
                           Thread.Sleep(50);
                          }
                    }
                }
    
     public void Update_PicBox()
            {
                if (pictureBox1.InvokeRequired)
                {
                    update u = new update(Update_PicBox);
                    pictureBox1.Invoke(u);
                }
                else
                {
                    pictureBox1.Update();
                }
            }
            private void Form1_Load(object sender, EventArgs e)
            {
                pictureBox1.Image = new Bitmap(@"C:\Image.jpg");
    
                Thread T1 = new Thread(Block);
                T1.Start();
            }
    private void checkBox1_CheckedChanged(object sender, EventArgs e)
            {
                if (checkBox1.Checked)
                {
                    Flag = 1;
                }
                else
                {
                    Flag = 0;
                    Update_PicBox();
                    pictureBox1.Image.Refresh();\\this line giaves an error: CS106 'Image' does not contain a definition for 'Refresh' and no extension method 'Refresh' accepting a first argument of type 'Image' could be found (are you missing a using directive or an assembly reference?)
    
                }
            }
        }
    • RodStephens says:

      You have a couple of options. First you can draw the points in the PictureBox’s Paint event handler. Use code in the event handler to determine whether it should draw one or both points. To remove the second point, just refresh the PictureBox (not it’s Image).

      Alternatively you could save a copy of the original image when the program starts. Later you can use that to reset the PictureBox’s image.

      • SaiNave says:

        Thank you for the reply, Mr. Rod, when I use “PictureBox.Refresh()” command it does not work and not meets the program result requirements
        Can you tell me how could I save the picture box and reset it
        Imean what commands should I use it for?
        please help

        • RodStephens says:

          Calling the PictureBox’s Refresh method makes it raise its Paint event. You can handle that event and draw whatever needs to be drawn.

          • SaiNave says:

            you mean :
            private void PictureBox1_Paint(object sender, PaintEventArgs e) under this ?

          • RodStephens says:

            Yes. In the Form Designer, select the PictureBox. Then in the Properties window, click the events icon (a lightning bolt). Find the Paint event and double-click it to create an event handler for it.

            Later if you call PictureBox1.Refresh(), it will invoke the event handler.

  9. SaiNave says:

    thank you Mr.Rod for the reply
    One more thing I want to ask, that I put the graphics plotting methods under the PictureBox paint event handler. because in my program I require one graphics refresh (or update )all the time in the program while the tracking plot should be active when the checkbox is checked and get deactivate when the checkbox is unchecked
    Please help me in this I have already spent a lot of time on this.

    • RodStephens says:

      To make it refresh constantly, make a Timer and have its Tick event handler call Refresh. If you go to the Search page and search for “graph timer” you should see some examples.

      To not draw when the checkbox is unchecked, make the Paint event handler first check the box and exit with a Return statement if it isn’t checked.

      if (!checkbox.Checked) return;

      • SaiNave says:

        Thank you for your reply
        If I create two threads for each plot so is it possible to combine both the plots at same picture box?

        • SaiNave says:

          Thank you for your reply.
          Actually, I load the image first in the PictureBox and draw points on an image in a picture box. If I called the PictureBox paint event handler for drawing points so is it appropriate to load an image in a PictureBox under Form Load event handler?

          • RodStephens says:

            Normally you should either draw in the Paint event handler or set its Image property but not both. If you use an image, the Paint event draws it on top of any drawing that you do so you don’t see it.

            Either draw on the image and then display it, or don’t use an image.

            (You can also use DrawImage to draw the image in the Paint event handler and then draw on top of it, but it’s easier to just draw on the image and then display it in the Image property.)

            You might want to look at these examples:

        • RodStephens says:

          That’s kind of hard to do. Only the UI thread can modify the user interface, so the threads would have to use Invoke to call another method on the UI thread to do the actual drawing.

Leave a Reply

Your email address will not be published. Required fields are marked *