确定哪个控件最接近鼠标指针

Jon*_*n B 5 .net c# graphics controls winforms

在我的C#(.NET 2)应用程序中,我想确定哪个控件是鼠标的壁橱.

我可以想到一些方法,这样做不会很正常.我可以使用该Control.Location属性,但这只是给我上/下,鼠标可能在控件的另一侧.我可以计算一个控件的中心点,但是大的控件会使这个偏斜(靠近控件的边缘计算为接近控件).

所以基本上我在画布上有一堆矩形和一个点.我需要找到离点最近的矩形.

(理想情况下,我也想知道点和矩形之间的距离).

有任何想法吗?

Jam*_*ing 3

您需要找到以下信息:
- 到最近角的距离
- 到最近边缘的距离
- (可选)到中心的距离

基本上,您需要这三个值中较小的一个。取两个控件的最小值来确定哪个更接近。

从加载表单开始,通过迭代表单上的所有控件并创建下面的类的集合。

要找到最接近某个点的控件,请迭代该集合(请参阅底部的代码)。使用迄今为止发现的最小距离来跟踪控件。如果您愿意,您可以测试 ContainsPoint()...如果您找到一个控制点落在控制范围内,则您已经获得了控制(只要您没有重叠的控制)。否则,当您到达集合的末尾时,您找到的与中心/边缘距离最短的控件就是您的控件。

public class HitControl {

    public Control ThisControl;

    private Rectangle ControlBounds;
    private Point Center;

    public HitControl (Control FormControl) {
        ControlBounds = FormControl.Bounds;
        Center = new Point(ControlBounds.X + (ControlBounds.Width/2), ControlBounds.Y + (ControlBounds.Height/2));
    }

    //  Calculate the minimum distance from the left, right, and center
    public double DistanceFrom(Point TestPoint) {

        //  Note:  You don't need to consider control center points unless
        //  you plan to allow for controls placed over other controls... 
        //  Then you need to test the distance to the centers, as well, 
        //  and pick the shortest distance of to-edge, to-side, to-corner

        bool withinWidth = TestPoint.X > ControlBounds.X && TestPoint.X < ControlBounds.X + ControlBounds.Width;
        bool withinHeight = TestPoint.Y > ControlBounds.Y && TestPoint.Y < ControlBounds.Y + ControlBounds.Height;

        int EdgeLeftXDistance = Math.Abs(ControlBounds.X - TestPoint.X);
        int EdgeRightXDistance = Math.Abs(ControlBounds.X + ControlBounds.Width - TestPoint.X);

        int EdgeTopYDistance = Math.Abs(ControlBounds.Y - TestPoint.Y);
        int EdgeBottomYDistance = Math.Abs(ControlBounds.Y + ControlBounds.Height - TestPoint.Y);

        int EdgeXDistance = Math.Min(EdgeLeftXDistance, EdgeRightXDistance);
        int EdgeYDistance = Math.Min(EdgeTopYDistance, EdgeBottomYDistance);


        // Some points to consider for rectangle (100, 100, 100, 100):
        //  - (140, 90):  Distance to top edge
        //  - (105, 10):  Distance to top edge
        //  - (50, 50):   Distance to upper left corner
        //  - (250, 50):  Distance to upper right corner
        //  - (10, 105):  Distance to left edge
        //  - (140, 105):  Distance to top edge
        //  - (105, 140):  Distance to left edge
        //  - (290, 105):  Distance to right edge
        //  - (205, 150):  Distance to right edge
        //  ... and so forth


        //  You're within the control
        if (withinWidth && withinHeight) {
            return Math.Min(EdgeXDistance, EdgeYDistance);
        }

        //  You're above or below the control
        if (withinWidth) {
            return EdgeYDistance;
        }

        //  You're to the left or right of the control
        if (withinHeight) {
            return EdgeXDistance;
        }

        //  You're in one of the four outside corners around the control.
        //  Find the distance to the closest corner
        return Math.Sqrt(EdgeXDistance ^ 2 + EdgeYDistance ^ 2);


    }

    public bool ContainsPoint (Point TestPoint) {
        return ControlBounds.Contains(TestPoint);
    }


}



//  Initialize and use this collection
List<HitControl> hitControls = (from Control control in Controls
                                select new HitControl(control)).ToList();

Point testPoint = new Point(175, 619);
double distance;
double shortestDistance = 0;
HitControl closestControl = null;

foreach (HitControl hitControl in hitControls) {

    //  Optional... works so long as you don't have overlapping controls
    //  If you do, comment this block out
    if (hitControl.ContainsPoint(testPoint)) {
        closestControl = hitControl;
        break;
    }

    distance = hitControl.DistanceFrom(testPoint);
    if (shortestDistance == 0 || distance < shortestDistance) {
        shortestDistance = distance;
        closestControl = hitControl;
    }
}

if (closestControl != null) {
    Control foundControl = closestControl.ThisControl;
}
Run Code Online (Sandbox Code Playgroud)