当一个点(应该)在一个矩形内时,PtInRect 不拾取

PtInRect not picking up when a point (should) be within a rect

我有一个 Win32 程序,我需要在其中检测按钮是否已被单击,但是由于按钮位于另一个控件(选项卡控件)的顶部,该按钮的默认功能已被破坏。我的解决方案是尝试手动检测点击,如下所示:

//within WM_NOTIFY:
case TCN_SELCHANGING: 
        {
            RECT rcButton;
            POINT pt;
            int i = 0;

            ScreenToClient(hWnd, &pt); //"hWnd" is the main window

            GetClientRect(button, &rcButton); //"button" is the button's HWND handler

            if (PtInRect(&rcButton, pt)) {
                  MessageBox(hWnd, L"Wonderful! Button was clicked!", L"Info", MB_OK | MB_ICONINFORMATION);
                  return TRUE; //stop selection from changing if button was clicked
            }
                
            return FALSE; //otherwise, allow selection to change
        }

这似乎不起作用,因为我没有看到消息框。

我在文档中读到我可能需要“规范化”我的 RECT。是这里的问题吗?如果可以,我该怎么做?

感谢您的帮助。

您的 POINT pt; 变量在您调用 ScreenToClient(hWnd, &pt); 未初始化 ,因此在调用 PtInRect(&rcButton, pt) 时它的值是无效的。在输入时,您必须指定要 ScreenToClient() 转换为客户端坐标的屏幕坐标。

您可以使用GetCursorPos()获取鼠标光标的当前屏幕坐标。

但是,您正在尝试将屏幕坐标转换为主 window 中的客户端坐标,而不是在按钮中。尝试更像这样的东西:

//within WM_NOTIFY:
case TCN_SELCHANGING: 
{
    POINT pt;
    RECT rcButton;

    GetCursorPos(&pt);
    ScreenToClient(button, &pt);

    GetClientRect(button, &rcButton);

    if (PtInRect(&rcButton, pt))
    {
        MessageBox(hWnd, L"Wonderful! Button was clicked!", L"Info", MB_OK | MB_ICONINFORMATION);
        return TRUE; //stop selection from changing if button was clicked
    }
                
    return FALSE; //otherwise, allow selection to change
}

或者,您可以获取按钮的客户端矩形,将其转换为屏幕坐标,然后将其与鼠标的屏幕坐标进行比较:

//within WM_NOTIFY:
case TCN_SELCHANGING: 
{
    RECT rcButton;
    POINT pt;

    GetClientRect(button, &rcButton);
    MapWindowPoints(button, NULL, (LPPOINT)&rcButton, 2);

    GetCursorPos(&pt);

    if (PtInRect(&rcButton, pt))
    {
        MessageBox(hWnd, L"Wonderful! Button was clicked!", L"Info", MB_OK | MB_ICONINFORMATION);
        return TRUE; //stop selection from changing if button was clicked
    }
                
    return FALSE; //otherwise, allow selection to change
}

话虽如此,可以使用鼠标或键盘更改选项卡选择。在您的情况下,您只需要单击鼠标,但 TCN_SELCHANGING 不会告诉您选项卡选择发生变化的原因。为此,您必须子类化选项卡控件以处理 left-click 的 WM_LBUTTONDOWN 消息和箭头、Home 和 End 键的 WM_KEYDOWN 消息。然后您可以相应地标记您的 TCN_SELCHANGING 处理程序。