在我的C#(.NET 2)应用程序中,我想确定哪个控件是鼠标的壁橱。
我可以想到一些方法可以做到这一点,但这些方法不会正常工作。我可以使用Control.Location
属性,但这只是给我上/下,鼠标可能在控件的另一侧。我可以计算一个控件的中心点,但是大的控件会使这个偏斜(靠近控件的边缘计算为靠近控件)。
所以基本上我在画布上有一堆矩形和一个点。我需要找到离点最近的矩形。
(理想情况下,我也想知道点和矩形之间的距离)。
有什么想法吗?
答案 0 :(得分: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;
}
答案 1 :(得分:1)
首先检查该点是否在任何rectangle中。如果没有,您可以使用this中的算法找到您的点与每个线段之间的距离。 您还可以找到控件的4个段,因此您有一个包含四个段的列表(首次启动)(确定控制面),现在您可以找到最近的段,即最近的矩形。
答案 2 :(得分:0)
你必须考虑矩形:)
然后你必须知道你感兴趣的控件,例如,窗体是一个控件..
答案 3 :(得分:0)
对于初学者,创建方法将计算从矩形边到某个任意点的距离。此方法的签名应为:
double DistanceFrom(Rect r, Point p);
然后,对于最简单的尝试,迭代所有控件,计算距离,记住最小距离并控制提供它。
对于矩形距离,请检查this。
编辑:
事实上,你可以维护一个排序的控件列表,这样你就可以随时拥有一个更靠近顶部的控件,并在鼠标移动时保持该列表 - 在速度方面可以证明它更有效。有趣的问题虽然:)
答案 4 :(得分:0)
我同意丹尼尔的意见,我们需要: double DistanceFrom(Rect r,Point p);
但在此之前,我们需要: double DistanceFrom(Line r,Point p); 和 double AngleBetweenPoints(Point p1,Point p2);