Browse DevX
Sign up for e-mail newsletters from DevX


GDI+ Drawing Page, Part I : Page 6

With the .NET Forms and Drawing class libraries you can create a drawing application C! la Visio that allows users to drag and draw shapes, select those shapes, and move them about the form.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Selecting and Moving Elements
The next requirement to tackle is to allow a user to select and then drag a graphical element on the page. This will again involve our mouse events (MouseDown, MouseMove, and MouseUp). From an algorithm perspective, the code needs to handle the following sequence of events:

  1. Determine when the user clicks the mouse and they are not intending to draw.
  2. Check to see if the user's click intersects with any of their previously drawn elements.
  3. Visually indicate the selection to the user.
  4. Re-draw the element as the user moves it about the page.
  5. Re-lock the element on the page.
The first requirement is obviously the simplest, just an If statement inside of the MouseDown event (see Listing 1).

As for the second requirement, you need to write code to solve a common problem called "hit-testing." Hit-testing involves capturing the point of the user's cursor at the time of their click and then determining if that captured point is within the bounds of any other element.

For simplicity sake, in this version, the code only supports single item select (no multi-select) and drag. In addition, elements are hit-tested in the reverse order that they were drawn to the screen (or added to the Elements collection class). This way, if two elements overlapped, the top-most Element would be selected every time. Let's look at the code that handles this.

First, add a routine to the Elements collection class called GetHitElement. This routine takes a Point (testPoint) type that represents the user's click (and our testing point). The routine returns the hit (or user selected) element (or a null in the case of no selection). You call this method from the MouseDown event on the control:

   Element el =  
Inside the GetHitElements method you simply loop the collection backwards and call each Element's internal HitTest method as follows:

   //search the list backwards
   for (int i=this.List.Count; i>0; i--)
      Element e = (Element)this.List[i-1];
   if (e.HitTest(testPoint))
   return e;
Next you need to make each concrete Element class expose their own HitTest method. This is required because each element's shape can be different (rectangle vs. ellipse, for example). Thankfully, GDI+ makes hit-testing pretty simple. First create a System.Drawing.Drawing2D.GraphicsPath instance:

   GraphicsPath gp = new GraphicsPath();
You'll use the GraphicsPath object to contain a version of the given Element. Therefore, you add the element to the graphics path:

     new Rectangle(this.Position, this.Size));
Next, you check the value of the IsVisible property of the GraphicsPath instance to determine if the user's click point is inside the element:

   return gp.IsVisible(testPoint);
If the call to IsVisible returns true, you have a hit. Once you have determined the user's selected object, you need to indicate that visually to the user. To do this you'll add code to the PageControl's MouseDown event. Once again you'll leverage the object model. Now set the hit element to the Document's SelectedElement property, which allows you to add code to the control's OnPaint event that checked to make sure that a SelectedElement exists. If so, the Paint event tells the selected element to draw itself as follows:

   if(m_doc.SelectedElement != null)
Of course, you have to create a DrawSelected method for each concrete Element class. In this case, to represent selection the code will just draw the object's outline in blue since the application does not allow the user to create objects with anything other than black pens.

Finally, to illustrate movement of the selected element about the page, you reset the selected element's Position property to that of the newly moved-to position. Before doing this, you need to set the moved point's offset values based on a difference calculated in the MouseDown event:

   mp.Offset(m_xDiff, m_yDiff);
   m_doc.SelectedElement.Position = mp;

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date