Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 命中测试矩形_C++_Windows_Winapi_Detection_Hit - Fatal编程技术网

C++ 命中测试矩形

C++ 命中测试矩形,c++,windows,winapi,detection,hit,C++,Windows,Winapi,Detection,Hit,我正在做一个项目,我有几个矩形,我希望每个矩形都有一个悬停效果。现在我知道我可以捕获WM_MOUSEMOVE消息并遍历每个矩形。但是如果我有很多矩形(如果50是很多的话)会怎么样呢 我可能是错的,但是如果每次鼠标移动时都重复这么多,并对每一个进行测试,应用程序的速度是否会降低一点 然后我开始思考操作系统(如windows)是如何做到这一点的,现在我的屏幕上有100多个东西,当我悬停在它们上面时,它们都有某种动画。我不认为每次鼠标移动一个像素时,windows都会遍历所有这些对象 基本上: 1.如

我正在做一个项目,我有几个矩形,我希望每个矩形都有一个悬停效果。现在我知道我可以捕获WM_MOUSEMOVE消息并遍历每个矩形。但是如果我有很多矩形(如果50是很多的话)会怎么样呢 我可能是错的,但是如果每次鼠标移动时都重复这么多,并对每一个进行测试,应用程序的速度是否会降低一点

然后我开始思考操作系统(如windows)是如何做到这一点的,现在我的屏幕上有100多个东西,当我悬停在它们上面时,它们都有某种动画。我不认为每次鼠标移动一个像素时,windows都会遍历所有这些对象

基本上:
1.如果我有50个左右的矩形,我如何计算出鼠标在哪个矩形上,并考虑性能。
2.windows是如何做到这一点的?(我比任何东西都好奇,但如果它不复杂,也许我可以在我自己的程序中实现类似的东西?)


哦,它们都是矩形,不会旋转或做任何事情。

不要考虑性能。 如果你这样做了,那么测量它

鼠标事件是非常低级的事件,非常快。 Windows将鼠标消息放入队列,应用程序将读取或忽略这些消息。在鼠标事件处理程序中,检查鼠标所在的矩形是一个快速操作


如果你的“矩形”是windows控件(它们应该是这样的),那么你可以为每个控件设置一个鼠标侦听器,这样windows就会自动调用正确的处理程序。

在一段代码造成真正的瓶颈之前,我不会太在意性能。让我们假设你已经有了这样的瓶颈,并测量下面代码的性能(它在C语言中,但是我非常确信C++不会慢):

在我的电脑上打印上述代码:

运行时间:701ms。(每次迭代0.701us)

如您所见,点击测试50个矩形所需的时间不到一微秒。你真的认为这与创建奇特的悬停效果和你的程序所做的任何其他事情相比太长了吗?当然,只有你能回答这个问题


但我的故事的寓意是:不要试图预先优化,也不要花时间试图解决一个可能根本不存在的问题。

我同意,对于少量矩形(例如50个),依次测试每个矩形的明显方法可能是最快的

我猜Windows也会这么做。显然,除非鼠标指针在父窗口中,否则它不必测试子窗口,而且即使是设计最糟糕的对话框,也很少有超过一百个控件同时可见。具有大量命中测试区域(例如ListView、网格)的控件优化其自己的命中测试


如果你有成千上万个矩形,那么性能可能是一个问题,你可以使用其中一个。

这里的其他问题没有回答你的第2部分,所以我来试一试:

2.windows是如何做到这一点的?(我比任何东西都好奇,但如果它不复杂,也许我可以在我自己的程序中实现类似的东西?) 要意识到的是,即使你打开了几十个窗口,每个窗口都有许多工具栏,每个窗口都有许多项目,等等,每次你移动鼠标,窗口也不需要检查所有东西

Windows基本上分为两层:一层是HWNDs,这是Windows本身管理桌面空间细分的方式;通常在每个HWND中都有一个控件,该控件管理该HWND中自己的空间:一个列表框管理自己的列表项,一个选项卡控件管理自己的选项卡,一个HTML控件管理自己的HTML页面布局,等等。(或者,在您的例子中,代码管理50个左右的矩形。)

当鼠标移动时,Windows首先确定要将WM_MOUSEMOVE发送到的正确HWND。它通过遍历HWNDs来实现这一点。HWND存储为一棵树,表示包含,同级之间的顺序表示Z顺序,因此Windows可以在此树中进行简单的深度优先下降,以找出任何给定点最底部的HWND。如果启动Spy++应用程序,您可以亲自查看此HWND树的外观。请注意,Windows并没有进行完全彻底的遍历:例如,在遍历顶级应用程序窗口以查找该点所在的应用程序时,一旦Windows找到包含该点的第一个顶级HWND,它将钻取该点,完全忽略它下面/后面的所有其他应用程序,以及其中的所有控件。这是一个关键,意味着windows只需遍历相对较少的HWD,即使屏幕上同时有许多可见的HWD

一旦Windows确定了正确的HWND,它就会向该控件发送适当的消息(WM_NCHITTEST、WM_MOUSEMOVE等),然后由该控件对其自己的内容执行同样的操作。对于包含固定大小项目的列表框,在特定点确定项目可能与除法操作一样简单;或者对于HTML控件,该控件可能有其自己的等价物,相当于一个“布局树”,它可以使用它来遍历一个元素,从而在该点上快速确定元素。在您的例子中,循环遍历矩形列表可能是非常好的

这是一个稍微简化的版本:它比上面的版本要复杂一点——例如,windows不仅仅在rect检查中达到一个点,还有其他检查允许奇数形状和透明的窗口(以及不可见和禁用的窗口);但基本的树下降思想适用

另一个需要记住的重要问题是,所有这些都非常快:移动鼠标发生在“人类时间”,现代CPU可以在鼠标在屏幕上移动几个像素的时间内完成许多操作。最后,请注意,当您将鼠标从屏幕上的点A移动到点B时,鼠标不会移动
public class Rectangle
{
    public int X { get; set; }
    public int Y { get; set; }
    public int W { get; set; }
    public int H { get; set; }

    public bool HitTest(int x, int y)
    {
        return x >= X && x < X + W && y >= Y && y < Y + H ? true : false;
    }
}
void PerformanceTest()
{
    const int Iterations = 1000000;
    Random rnd = new Random();
    var rectangles = Enumerable.Range(1, 50).Select(
            r => new Rectangle {
                X = rnd.Next(1000),
                Y = rnd.Next(1000),
                W = rnd.Next(1000),
                H = rnd.Next(1000)}).ToList();

    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < Iterations; i++)
    {
        rectangles.ForEach(r => r.HitTest(500, 500));
    }
    sw.Stop();

    Console.WriteLine("Elapsed time: {0}ms. ({1}us per one iteration)",
        sw.ElapsedMilliseconds,
        (float)sw.ElapsedMilliseconds * 1000 / Iterations);
}
return ... ? true : false;