Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

[tut 3] Graphics Program using C# Drag & Drop & Delete Objects

4.50/5 (3 votes)
7 Apr 2016CPOL5 min read 21.1K   1.7K  
Part 3 of a tutorial to show a graphics program using C# using GDI and SVG drag and drop and delete objects

Introduction

This is the third tutorial of a series of tutorials on how to build a graphics program using C# in Windows Form that exports the artwork in a vector format:

.... also, you would understand how to move, delete, Ctrl Z your vector art and save it in a special format to be read by your program again.

Also, we will learn how to save XML files... how to export in verilog format... how to use a star algorithm... how to use hand tool... how to manually create the Ctrl Z technique.

What you will be capable of building:

Here in this tutorial, we will start by going through how to make your C# program draw a specific svg path.

Continuing from where we stopped last time .. today, we are going to discuss how to drag and drop objects:

  1. Some modifications to start with
  2. Adding mouse move function

Background

Using the Code

1. So Let's Start With Some Modifications to Our Previous Code

As we are going to move objects, we need to remove any king of buffering so let's write this line of code in our main function:

C++
this.DoubleBuffered = true;  //will remove any buffering

Also let's add some private data members to tell which object was selected and to tell if we selected any element yet or not:

C#
int selected=0;
bool is_selected = false;

Add a new key listener to listen for the move command so in Form1_KeyDown:

C#
else if (e.KeyData == Keys.M)
          {
              action = "move";
          }

We would also require a member to hold the value of the left mouse click.

Another one to old a bool identifying if it was the first time you dragged a object to make a loop and to know which object you selected... otherwise, it would loop through each time you move the mouse and create a rectangle that would be used as a selection boundary box.

private members

C#
MouseButtons m = MouseButtons.Left;
bool first = true;
RectangleF selected_recatngle = new RectangleF();

Also, I have modified the sData of the heart to be:

C#
private string sData = "M97.5,181.5c-4.5-5-15.6-14.8-24.8-21.7c-27.2-20.5-30.9-23.
5-41.9-33.7c-20.4-18.7-29-37.6-29-63.1c0-12.5,0.9-17.3,4.4-24.6C12,25.9,20.8,16.7,
31.9,11c7.9-4,11.8-5.8,25-5.9c13.8-0.1,16.7,1.5,24.8,6c9.9,5.4,20.1,17,22.2,25.3l1.3,
5.1l3.2-7c18.1-39.6,75.9-39,96,1c6.4,12.7,7.1,39.8,1.4,55.1c-7.4,19.9-21.2,35.1-53.3,
58.4c-21,15.3-44.8,38.3-46.4,41.6C104.2,194.2,106,191,97.5,181.5z";

Now let's make our application more like a graphics application by simply going to the designer and changing back color to white under properties>>back color >>white:

Image 1

2. Now Let's Work on Our Drag Drop Functionality

Start by going to the designer of your form and add a mouse move action:

Image 2

Then if we go to the back code, we will see private void Form1_MouseMove(object sender, MouseEventArgs e) created.

We need to start our dragging once the user uses this method ... so the selection technique will only occur in the first time the user uses this function... and once this technique is finished any time the user continues on selecting the object the program won't have to re calculate which object was selected.. so to sum things up ... the program will only loop through the list the first time the user uses the function .. and when he continues on moving this object, the program won't have to re calculate which object ... this will be implemented by a condition when the user first uses this function:

C#
private void Form1_MouseMove(object sender, MouseEventArgs e)
      {
       if (first == true && e.Button == m && action.Equals("move"))
      {
      }
  }

This will check if it was your first time to enter this function and if you entered it using the left mouse button and if the action was a move action.

Now we need to iterate through our list to know which object was selected ... so first write the foreach loop to iterate... then, we will put the condition to see if the point of selection was inside any shape of them:

C#
if (sh.draw_svg().Path(render).GetBounds().Contains(e.Location))

Then inside this function, let us define the rectangle that would be used to define the boundaries of the rectangle and set the selected int to the counter to know which object was selected and set the bool of selection to true if this happens to break the foreach loop else set the is_selected to false and of course never forget to increment your counter and if you entered in this condition, then it is your first time ... then the next time you move the object, you won't require it to enter in this condition so simply set first to false:

C#
private void Form1_MouseMove(object sender, MouseEventArgs e)
       {
           if (first == true && e.Button == m && action.Equals("move"))
           {
               int counter = 0;
               foreach (shapes sh in shape_list)
               {
                   if (sh.draw_svg().Path(render).GetBounds().Contains(e.Location))
                   {
                       selected_recatngle = sh.draw_svg().Path(render).GetBounds();
                       selected = counter;
                       is_selected = true;
                       break;
                   }

                   else
                   {
                       is_selected = false;
                   }
                   counter++;
               }
               first = false;
           }

All the previous was just to define what was the selected shape ... we really need to move it... just first update the bounding rectangle ..then we simply modify the translateX and translateY properties inside the shape class... and call the on paint function ..

If the object was not selected, it will go to the next else condition to reset first bool to false... so that when you select another shape next time you enter in the function handling knowing which object you selected:

C#
if (is_selected == true && e.Button == m && action.Equals("move"))
           {
               selected_recatngle.Location = e.Location;
               shape_list.ElementAt<shapes>(selected).translateX = e.X;
               shape_list.ElementAt<shapes>(selected).translateY = e.Y;
               Invalidate();
           }
           else
           {
               first = true;
           }

So the final mouse move would be like this:

Image 3

C#
private void Form1_MouseMove(object sender, MouseEventArgs e)
     {

  if (first == true && e.Button == m && action.Equals("move"))
         {
             int counter = 0;
             foreach (shapes sh in shape_list)
             {
                 // if (sh.draw_svg().Path(render).GetBounds().Contains(e.Location))
                 //inefficient
                 if (sh.draw_svg().Path(render).IsVisible(e.Location))//more efficient
                 {
                     selected_recatngle = sh.draw_svg().Path(render).GetBounds();
                     selected = counter;
                     is_selected = true;
                     break;
                 }

                 else
                 {
                     is_selected = false;
                 }
                 counter++;
             }
             first = false;
         }

         if (is_selected == true && e.Button == m && action.Equals("move"))
         {
             selected_recatngle.Location = e.Location;
             shape_list.ElementAt<shapes>(selected).translateX = e.X;
             shape_list.ElementAt<shapes>(selected).translateY = e.Y;
             Invalidate();
         }
         else
         {
             first = true;
         }
     }

Now let's handle translateX and translateY in the shape members that were updated... simply add to the draw svg of both heart and star this matrix... to just shift the return value before it returns and apply this transform:

C#
Matrix m = new Matrix();
           m.Translate(translateX, translateY, MatrixOrder.Append);
           alu.Transform(m);

so that the final draw_svg in both heart and star would be:

C#
public override Svg.SvgPath draw_svg()
       {
           Svg.SvgPath pa = new Svg.SvgPath();
           Svg.Pathing.SvgPathSegmentList svgSvgPathSegmentList =
                                                new Svg.Pathing.SvgPathSegmentList();
           var converter = TypeDescriptor.GetConverter
                                          (typeof(Svg.Pathing.SvgPathSegmentList));
           pa.PathData = (Svg.Pathing.SvgPathSegmentList)converter.ConvertFrom(sData);

           Svg.ISvgRenderer render = null;

           GraphicsPath alu = new GraphicsPath();
           alu = pa.Path(render);
           //modification
           Matrix m = new Matrix();
           m.Translate(translateX, translateY, MatrixOrder.Append);
           alu.Transform(m);
           //modification
           region = new Region(pa.Path(render));

           return pa;
       }

Now let's draw the selected rectangle... let it be a dotted reb rectangle so in the onpaint function, add this code:

C#
Point p_temp = new Point((int)selected_recatngle.Location.X, (int)selected_recatngle.Location.Y);
            Size sssize = new System.Drawing.Size((int)selected_recatngle.Size.Width, 
                                                  (int)selected_recatngle.Size.Height);
            Rectangle rrrr = new Rectangle(p_temp, sssize);
            Pen selection_pen = new Pen(Brushes.Red, 2);
            selection_pen.DashStyle = DashStyle.Dot;
            e.Graphics.DrawRectangle(selection_pen, rrrr);

The purpose of the above lines is simply to convert RectangleF to a normal rectangle to be drawn and then to be drawn using a red dashed pen.

Now to delete a specific object, just simply modify in the Form1_KeyDown handler:

C#
else if (e.KeyData == Keys.Delete && is_selected==true)
           {
               shape_list.RemoveAt(selected);
               RectangleF null_rectangle = new RectangleF();
               selected_recatngle = null_rectangle;
               is_selected = false;
               Invalidate();
           }

As we before in the mouse move identified the selected, so just remove it from the list and make the selection rectangle points to null.

Image 4

 
it would be very important for me to know what do you think these tutorials ... are they up to what you have expected ?? ... it would be really important for me to hear your feedback

History

  • 8th March, 2016: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)