8.2 Perform Hit Testing with Shapes


8.2 Perform Hit Testing with Shapes

Problem

You need to detect if a user clicks inside a shape.

Solution

Test the point where the user clicked with methods such as Rectangle.Contains and Region.IsVisible (in the System.Drawing namespace), or GraphicsPath.IsVisible (in the System.Drawing.Drawing2D namespace), depending on the type of shape.

Discussion

Often, if you use GDI+ to draw shapes on a form, you need to be able to determine when a user clicks inside a given shape. The .NET Framework provides three methods that can help with this task:

  • The Rectangle.Contains method, which takes a point and returns true if the point is inside a given rectangle. In many cases, you can retrieve a rectangle for another type of shape. For example, you can use Image.GetBounds to retrieve the invisible rectangle that represents the image boundaries. The Rectangle struct is a member of the System.Drawing namespace.

  • The GraphicsPath.IsVisible method, which takes a point and returns true if the point is inside the area defined by a closed GraphicsPath . Because a GraphicsPath can contain multiple lines, shapes, and figures, this approach is useful if you want to test if a point is contained inside a nonrectangular region. The GraphicsPath class is a member of the System.Drawing.Drawing2D namespace.

  • The Region.IsVisible method, which takes a point and returns true if the point is inside the area defined by a Region . A Region , like the GraphicsPath , can represent a complex nonrectangular shape. Region is a member of the System.Drawing namespace.

The following example shows a form that creates a Rectangle and a GraphicsPath . By default, these two shapes are given light blue backgrounds. However, an event handler responds to the Form.MouseMove event, checks to see if the mouse pointer is in one of these shapes, and updates the background to bright pink if the pointer is there.

 using System; using System.Windows.Forms; using System.Drawing; using System.Drawing.Drawing2D; public class HitTesting : System.Windows.Forms.Form {     // (Designer code omitted.)     // Define the shapes used on this form.     private GraphicsPath path;     private Rectangle rectangle;     // Define the flags that track where the mouse pointer is.     private bool inPath = false;     private bool inRectangle = false;     // Define the brushes used for painting the shapes.     Brush highlightBrush = Brushes.HotPink;     Brush defaultBrush = Brushes.LightBlue;     private void HitTesting_Load(object sender, System.EventArgs e) {              // Create the shapes that will be displayed.         path = new GraphicsPath();         path.AddEllipse(10, 10, 100, 60);         path.AddCurve(new Point[] {new Point(50, 50),                       new Point(10,33), new Point(80,43)});         path.AddLine(50, 120, 250, 80);         path.AddLine(120, 40, 110, 50);         path.CloseFigure();         rectangle = new Rectangle(100, 170, 220, 120);     }     private void HitTesting_Paint(object sender,        System.Windows.Forms.PaintEventArgs e) {              Graphics g = e.Graphics;         // Paint the shapes according to the current selection.         if (inPath) {                      g.FillPath(highlightBrush, path);             g.FillRectangle(defaultBrush, rectangle);         }else if (inRectangle) {                      g.FillRectangle(highlightBrush, rectangle);             g.FillPath(defaultBrush, path);         }else {                      g.FillPath(defaultBrush, path);             g.FillRectangle(defaultBrush, rectangle);         }         g.DrawPath(Pens.Black, path);         g.DrawRectangle(Pens.Black, rectangle);     }     private void HitTesting_MouseMove(object sender,       System.Windows.Forms.MouseEventArgs e) {              Graphics g = this.CreateGraphics();         // Perform hit testing with rectangle.         if (rectangle.Contains(e.X, e.Y)) {                      if (!inRectangle) {                              inRectangle = true;                 // Highlight the rectangle.                 g.FillRectangle(highlightBrush, rectangle);                 g.DrawRectangle(Pens.Black, rectangle);             }         }else if (inRectangle) {                      inRectangle = false;             // Restore the unhighlighted rectangle.             g.FillRectangle(defaultBrush, rectangle);             g.DrawRectangle(Pens.Black, rectangle);         }         // Perform hit testing with path.         if (path.IsVisible(e.X, e.Y)) {                      if (!inPath) {                              inPath = true;                 // Highlight the path.                 g.FillPath(highlightBrush, path);                 g.DrawPath(Pens.Black, path);             }         }else if (inPath) {                      inPath = false;             // Restore the unhighlighted path.             g.FillPath(defaultBrush, path);             g.DrawPath(Pens.Black, path);         }         g.Dispose();     } } 

Notice that this highlighting operation takes place directly inside the MouseMove event handler. The painting is only performed if the current selection has changed. For simpler code, you could invalidate the entire form every time the mouse pointer moves in or out of a region and handle all the drawing in the Form.Paint event handler, but this would lead to more drawing and generate additional flicker as the entire form is repainted.

Figure 8.2 shows the application in action.

click to expand
Figure 8.2: Hit testing with a Rectangle and a GraphicsPath object.



C# Programmer[ap]s Cookbook
C# Programmer[ap]s Cookbook
ISBN: 735619301
EAN: N/A
Year: 2006
Pages: 266

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net