检查 X-Y 坐标是否位于保存在字典中的控件的范围内
Checking if X-Y co-ordinate lies within bounds of a control saved in a dictionary
我正在将 WinForm 控件的范围保存在字典中,例如:
Dictionary<Tuple<int, int>, Control> dictionary =
new Dictionary<Tuple<int, int>, Control>();
我正在以编程方式在 WinForm 上绘制控件。每当我绘制每个控件时,我都会将该控件的边界保存在此字典中,例如:
dictionary.Add(Tuple.Create(myControl.X, myControl.Y), myControl);
dictionary.Add(Tuple.Create(myControl.X + myControl.Length, myControl.Y), myControl);
dictionary.Add(Tuple.Create(myControl.X + myControl.Length, myControl.Y + myControl.Width), myControl);
dictionary.Add(Tuple.Create(myControl.X, myControl.Y + myControl.Width), myControl);
现在,我想要实现的是,每当鼠标点击 MouseEventArgs e 的 WinForm 时,我想检查 Point(e.X, e.Y) 是否在边界内有没有控件??
我知道我可以遍历字典的键值对并计算 Point(e.X,e.Y) 是否在边界内。但是我想避免遍历字典的Keys并得到解决方案。
知道如何在不遍历字典并计算每个点的情况下实现它吗?
迭代应该非常快,尤其是当您使用标准控件属性来确定它的位置和大小时。例如,此代码将生成 5000 个控件,给它们所有随机大小和位置,然后遍历每个控件并告诉您某个点是否位于其边界内。整个过程在我的机器上运行不到 0.4 秒:
var stopwatch = new Stopwatch();
stopwatch.Start();
Random rnd = new Random();
//Generate 500 controls with random positions
var controls = Enumerable.Range(0, 5000)
.Select(index => new Control
{
Top = rnd.Next(0, 1000),
Left = rnd.Next(0, 1000),
Width = rnd.Next(0, 1000),
Height = rnd.Next(0, 1000)
})
.ToList();
var controlsUnderMouse = controls
.Where(c => c.Bounds.Contains(150, 150))
.ToList();
Console.WriteLine($"Found {controlsUnderMouse.Count()} controls in {stopwatch.Elapsed}");
这将输出如下内容:
Found 106 controls in 00:00:00.3939616
如果您只想寻找一个控件,您可以将 Where
更改为 First
,这样 return 会更快。
试试这个。如果需要,可以将 int id
替换为 Control
。
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reactive.Linq;
using System.Windows.Forms;
namespace Anything
{
public class Program
{
public static void Main(string[] args)
{
var random = new Random();
var bounds = Screen.PrimaryScreen.Bounds;
var extents = new Dictionary<int, Rectangle>();
for (var i = 0; i < 300; i++)
{
var x = random.Next(bounds.Width);
var y = random.Next(bounds.Height);
var w = random.Next(bounds.Width - x);
var h = random.Next(bounds.Height - y);
extents[i] = new Rectangle(x, y, w, h);
}
var domains = from time in Observable.Interval(TimeSpan.FromMilliseconds(100))
from extent in extents
where extent.Value.Contains(Control.MousePosition)
select extent.Key;
var subscription = domains.Subscribe(id => Console.Write($"{id},"));
Console.ReadKey();
subscription.Dispose();
}
}
}
我正在将 WinForm 控件的范围保存在字典中,例如:
Dictionary<Tuple<int, int>, Control> dictionary =
new Dictionary<Tuple<int, int>, Control>();
我正在以编程方式在 WinForm 上绘制控件。每当我绘制每个控件时,我都会将该控件的边界保存在此字典中,例如:
dictionary.Add(Tuple.Create(myControl.X, myControl.Y), myControl);
dictionary.Add(Tuple.Create(myControl.X + myControl.Length, myControl.Y), myControl);
dictionary.Add(Tuple.Create(myControl.X + myControl.Length, myControl.Y + myControl.Width), myControl);
dictionary.Add(Tuple.Create(myControl.X, myControl.Y + myControl.Width), myControl);
现在,我想要实现的是,每当鼠标点击 MouseEventArgs e 的 WinForm 时,我想检查 Point(e.X, e.Y) 是否在边界内有没有控件??
我知道我可以遍历字典的键值对并计算 Point(e.X,e.Y) 是否在边界内。但是我想避免遍历字典的Keys并得到解决方案。
知道如何在不遍历字典并计算每个点的情况下实现它吗?
迭代应该非常快,尤其是当您使用标准控件属性来确定它的位置和大小时。例如,此代码将生成 5000 个控件,给它们所有随机大小和位置,然后遍历每个控件并告诉您某个点是否位于其边界内。整个过程在我的机器上运行不到 0.4 秒:
var stopwatch = new Stopwatch();
stopwatch.Start();
Random rnd = new Random();
//Generate 500 controls with random positions
var controls = Enumerable.Range(0, 5000)
.Select(index => new Control
{
Top = rnd.Next(0, 1000),
Left = rnd.Next(0, 1000),
Width = rnd.Next(0, 1000),
Height = rnd.Next(0, 1000)
})
.ToList();
var controlsUnderMouse = controls
.Where(c => c.Bounds.Contains(150, 150))
.ToList();
Console.WriteLine($"Found {controlsUnderMouse.Count()} controls in {stopwatch.Elapsed}");
这将输出如下内容:
Found 106 controls in 00:00:00.3939616
如果您只想寻找一个控件,您可以将 Where
更改为 First
,这样 return 会更快。
试试这个。如果需要,可以将 int id
替换为 Control
。
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reactive.Linq;
using System.Windows.Forms;
namespace Anything
{
public class Program
{
public static void Main(string[] args)
{
var random = new Random();
var bounds = Screen.PrimaryScreen.Bounds;
var extents = new Dictionary<int, Rectangle>();
for (var i = 0; i < 300; i++)
{
var x = random.Next(bounds.Width);
var y = random.Next(bounds.Height);
var w = random.Next(bounds.Width - x);
var h = random.Next(bounds.Height - y);
extents[i] = new Rectangle(x, y, w, h);
}
var domains = from time in Observable.Interval(TimeSpan.FromMilliseconds(100))
from extent in extents
where extent.Value.Contains(Control.MousePosition)
select extent.Key;
var subscription = domains.Subscribe(id => Console.Write($"{id},"));
Console.ReadKey();
subscription.Dispose();
}
}
}