Getting shape under mouse cursor

Oct 30, 2012 at 5:52 AM

Hi,

to get shape under mouse cursor I'm using the following code:

// In the form:
private void display1_MouseMove(object sender, MouseEventArgs e)
{
    if (this.display1.Diagram != null)
    {
        Shape shape = this.display1.Diagram.FindShape<Shape>(e.Location);
        if (shape != null)
        {
            Console.WriteLine("Shape '{0}' found at '{1}'", shape.GetType().Name, e.Location);
        }
    }
}

// In the "Extensions" static class:
public static T FindShape<T>(this Diagram diagram, Point pt) where T : Shape
{
    foreach (Shape shape in diagram.Shapes)
    {
        if (shape is T && shape.GetBoundingRectangle(false).Contains(pt))
            return shape as T;
    }
    return null;
}

This code doesn't work properly. I'm sure the reason is I need to convert (offset) e.Location from Display coordinates to Diagram coordinates and only then pass them to FindShape<> method. However, I couldn't find a way to make this conversion: Diagram has no X, Y (or Location) properties!

What's the solution?

Oct 30, 2012 at 6:49 AM
Edited Oct 30, 2012 at 7:15 AM

Found the solution myself: Display.ControlToDiagram() method.

private Point _previousLocation = Point.Empty;
private void display1_MouseMove(object sender, MouseEventArgs e)
{
    if (this.display1.Diagram != null)
    {
        Point pt = Point.Empty;
        this.display1.ControlToDiagram(e.Location, out pt);
        Shape shape = this.display1.Diagram.FindShape<Shape>(pt);
        if (_previousLocation != pt)
        {
            _previousLocation = pt;
            if (shape != null)
                _toolTip.SetToolTip(this.display1, shape.GetType().Name);
            else
                _toolTip.RemoveAll();
        }
    }
}

Had to use _previousLocation variable because due to some strange reasons Display.MouseMove event is fired even when there is NO any mouse movement! Seems this event is fired periodically, with some timer. Are you sure this is right?

One question more:

Which method is better to use: Shape.GetBoundingRectangle(false).Contains(pt) or Shape.ContainsPoint(x,y)?

Coordinator
Oct 30, 2012 at 9:44 AM

There is no timer firing any mouse events - except if you press the middle mouse button for "universal scroll".

GetBoundingRectangle returns the X axis aligned bounding rectangle of the shape. In your very special case (rectangular shapes that are not rotatable), the bounding rectangle may be identical to the shape's outline but in general it is not. I would strongly recommend to use ContainsPoint().

Oct 30, 2012 at 9:48 AM
KurtHolzinger wrote:

There is no timer firing any mouse events - except if you press the middle mouse button for "universal scroll".

Then it may be a problem with my mouse optics :)

KurtHolzinger wrote:

GetBoundingRectangle returns the X axis aligned bounding rectangle of the shape. In your very special case (rectangular shapes that are not rotatable), the bounding rectangle may be identical to the shape's outline but in general it is not. I would strongly recommend to use ContainsPoint().

Thank you!