C# 确定最接近鼠标指针的控件

C# 确定最接近鼠标指针的控件,c#,.net,winforms,graphics,controls,C#,.net,Winforms,Graphics,Controls,在我的C#(.NET2)应用程序中,我想确定哪个控件最靠近鼠标 我可以想出一些方法来做这件事,但这些方法不太管用。我可以使用控件.Location属性,但这只会让我看到上/左,鼠标可能在控件的另一侧。我可以计算控件的中心点,但大型控件会使其倾斜(接近控件的边缘视为接近控件) 基本上我在画布上有一堆矩形和一个点。我需要找到离点最近的矩形 (理想情况下,我也想知道点和矩形之间的距离) 有什么想法吗?你必须用矩形来思考:) 测试:鼠标在控制范围内吗 如果不是:离任何一条边有多远 然后您必须知道您感兴趣

在我的C#(.NET2)应用程序中,我想确定哪个控件最靠近鼠标

我可以想出一些方法来做这件事,但这些方法不太管用。我可以使用
控件.Location
属性,但这只会让我看到上/左,鼠标可能在控件的另一侧。我可以计算控件的中心点,但大型控件会使其倾斜(接近控件的边缘视为接近控件)

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

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


有什么想法吗?

你必须用矩形来思考:)

  • 测试:鼠标在控制范围内吗
  • 如果不是:离任何一条边有多远

  • 然后您必须知道您感兴趣的控件,例如,表单是一个控件。

    首先,创建一个方法,该方法将计算从矩形边到某个任意点的距离。此方法的签名应为:

    double DistanceFrom(Rect r, Point p);
    
    然后,对于最简单的尝试,迭代所有控件,计算距离,记住最小距离和提供它的控件

    对于矩形距离,请查看

    编辑:


    事实上,您可以维护一个已排序的控件列表,这样您就可以始终拥有第一个更靠近顶部的控件,并在鼠标移动时维护该列表-这可能证明在速度方面更有效。有趣的问题:)

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

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

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

    要找到离某个点最近的控件,请迭代该集合(请参见底部的代码)。以迄今为止发现的最小距离跟踪控制装置。如果需要,可以测试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;
    }
    
    公共类HitControl{
    公共控制;公共控制;
    私有矩形控制边界;
    私人点中心;
    公共控件(控件窗体控件){
    ControlBounds=FormControl.Bounds;
    中心=新点(ControlBounds.X+(ControlBounds.Width/2),ControlBounds.Y+(ControlBounds.Height/2));
    }
    //计算距离左侧、右侧和中心的最小距离
    公共双距离(测试点){
    /Note:你不需要考虑控制中心点,除非
    //您计划允许将控件放置在其他控件之上。。。
    //然后你还需要测试到中心的距离,
    //并选择到边、到边、到角的最短距离
    boolwithinwidth=TestPoint.X>ControlBounds.X&&TestPoint.XControlBounds.Y&&TestPoint.Y