C++ 在鼠标下滚动窗口

C++ 在鼠标下滚动窗口,c++,windows,winapi,mouseevent,messages,C++,Windows,Winapi,Mouseevent,Messages,如果查看Visual Studio 2012,您会注意到,如果使用鼠标滚轮,鼠标下的窗口将滚动,而不是聚焦窗口。也就是说,如果您将光标放在代码编辑器中,并将鼠标移动到解决方案资源管理器窗口上并滚动,则解决方案资源管理器将滚动,而不是代码编辑器。然而,WM_mouseweel消息只发送到聚焦窗口,因此在本例中,代码编辑器。我们如何实现我们的程序,使WM_鼠标滚轮消息在鼠标下滚动窗口,这是直观的,而不是聚焦窗口?显然,我们可以在程序的核心解决这个问题。查看消息循环的代码,它应该在WinMain方法中

如果查看Visual Studio 2012,您会注意到,如果使用鼠标滚轮,鼠标下的窗口将滚动,而不是聚焦窗口。也就是说,如果您将光标放在代码编辑器中,并将鼠标移动到解决方案资源管理器窗口上并滚动,则解决方案资源管理器将滚动,而不是代码编辑器。然而,WM_mouseweel消息只发送到聚焦窗口,因此在本例中,代码编辑器。我们如何实现我们的程序,使WM_鼠标滚轮消息在鼠标下滚动窗口,这是直观的,而不是聚焦窗口?

显然,我们可以在程序的核心解决这个问题。查看消息循环的代码,它应该在WinMain方法中:

while (GetMessage (&msg, NULL, 0, 0) > 0)
{
    TranslateMessage (&msg);
    DispatchMessage (&msg);
}
这里,我们只需要说,如果消息是WM_MOUSEWHEEL消息,我们希望将其传递到鼠标下的窗口,而不是焦点窗口:

POINT mouse;

while (GetMessage (&msg, NULL, 0, 0) > 0)
{
    //Any other message.
    if (msg.message != WM_MOUSEWHEEL)
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
    //Send the message to the window over which the mouse is hovering.
    else
    {
        GetCursorPos (&mouse);
        msg.hwnd = WindowFromPoint (mouse);
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
}

现在,鼠标下的窗口将始终显示滚动消息,而不是聚焦窗口。

显然,我们可以在程序的核心解决这个问题。查看消息循环的代码,它应该在WinMain方法中:

while (GetMessage (&msg, NULL, 0, 0) > 0)
{
    TranslateMessage (&msg);
    DispatchMessage (&msg);
}
这里,我们只需要说,如果消息是WM_MOUSEWHEEL消息,我们希望将其传递到鼠标下的窗口,而不是焦点窗口:

POINT mouse;

while (GetMessage (&msg, NULL, 0, 0) > 0)
{
    //Any other message.
    if (msg.message != WM_MOUSEWHEEL)
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
    //Send the message to the window over which the mouse is hovering.
    else
    {
        GetCursorPos (&mouse);
        msg.hwnd = WindowFromPoint (mouse);
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
}

现在,鼠标下的窗口将始终获得滚动消息,而不是聚焦窗口。

在应接收消息的父窗口和子窗口中处理WM_MOUSEWHEEL消息

在子窗口的WM_鼠标滚轮处理程序中执行以下操作:

    POINT mouse;
    GetCursorPos(&mouse);
    if (WindowFromPoint(mouse) != windowHandle)
    {
        // Sends the WM_MOUSEWHEEL message to your parent window
        return DefWindowProc(windowHandle, message, wParam, lParam);
    }
然后在父窗口的WM_鼠标滚轮处理程序中执行以下操作:

    POINT mouse;

    GetCursorPos(&mouse);
    HWND hwnd = WindowFromPoint(mouse);

    SendMessage(hwnd, message, wParam, lParam);

这样,如果子窗口具有焦点,另一个实际有鼠标指针悬停在其上的窗口将接收WM_MOUSEWHEEL消息。

在应接收消息的父窗口和子窗口中处理WM_MOUSEWHEEL消息

在子窗口的WM_鼠标滚轮处理程序中执行以下操作:

    POINT mouse;
    GetCursorPos(&mouse);
    if (WindowFromPoint(mouse) != windowHandle)
    {
        // Sends the WM_MOUSEWHEEL message to your parent window
        return DefWindowProc(windowHandle, message, wParam, lParam);
    }
然后在父窗口的WM_鼠标滚轮处理程序中执行以下操作:

    POINT mouse;

    GetCursorPos(&mouse);
    HWND hwnd = WindowFromPoint(mouse);

    SendMessage(hwnd, message, wParam, lParam);

这样,如果子窗口具有焦点,另一个实际有鼠标指针悬停在其上的窗口将接收WM_MOUSEWHEEL消息。

我发现在应用程序类中重写PreTranslateMessage函数要简单得多

BOOL MyApp::PreTranslateMessage(MSG* pMsg)
{
    POINT mouse;
    CWnd* windowUnderMouse;

    if (pMsg->message == WM_MOUSEWHEEL)
    {
        GetCursorPos(&mouse);       
        pMsg->hwnd = WindowFromPoint(mouse);
    }

    return CWinApp::PreTranslateMessage(pMsg);
}

希望它能帮助别人。

我发现在应用程序类中重写PreTranslateMessage函数要简单得多

BOOL MyApp::PreTranslateMessage(MSG* pMsg)
{
    POINT mouse;
    CWnd* windowUnderMouse;

    if (pMsg->message == WM_MOUSEWHEEL)
    {
        GetCursorPos(&mouse);       
        pMsg->hwnd = WindowFromPoint(mouse);
    }

    return CWinApp::PreTranslateMessage(pMsg);
}

希望它能帮助别人。

只是对前面答案的修改。 应使用嵌入在消息中的鼠标坐标,而不是当前坐标,如果消息处理延迟,它们可能会有所不同

BOOL CMyApp::PreTranslateMessage (MSG* pMsg)
{
    if (pMsg -> message == WM_MOUSEWHEEL)
        pMsg -> hwnd = WindowFromPoint (CPoint (GET_X_LPARAM (pMsg -> lParam), GET_Y_LPARAM (pMsg -> lParam)));

    return CWinAppEx::PreTranslateMessage (pMsg);
}

只是对先前答案的修改。 应使用嵌入在消息中的鼠标坐标,而不是当前坐标,如果消息处理延迟,它们可能会有所不同

BOOL CMyApp::PreTranslateMessage (MSG* pMsg)
{
    if (pMsg -> message == WM_MOUSEWHEEL)
        pMsg -> hwnd = WindowFromPoint (CPoint (GET_X_LPARAM (pMsg -> lParam), GET_Y_LPARAM (pMsg -> lParam)));

    return CWinAppEx::PreTranslateMessage (pMsg);
}

这是一个很好的想法,但不幸的是,
WM_mouseweel
被直接发送到具有焦点的窗口,因此它不会显示在
GetMessage
循环中。嗯,它似乎可以工作。我认为GetMessage仅在消息由SendMessage、SendMessageCallback、SendMessageTimeout或SendNotifyMessage(MSDN)发布时直接向windows发送消息,并为TranslateMessage和DispatchMessage检索所有其他消息,WM_MOUSEWHEEL就是其中之一。这很好地模拟了Windows 10中鼠标滚轮的新默认行为。对的调用仅对键盘输入消息有意义。您不需要在
WM\u mouseweel
处理程序中调用它。还请注意,当应用程序进入模式循环时(最明显的是在打开模式对话框时),此代码就会失败。这是一个不错的想法,但不幸的是,
WM_mouseweel
会直接发送到具有焦点的窗口,因此它不会显示在
GetMessage
循环中。嗯,它似乎可以工作。我认为GetMessage仅在消息由SendMessage、SendMessageCallback、SendMessageTimeout或SendNotifyMessage(MSDN)发布时直接向windows发送消息,并为TranslateMessage和DispatchMessage检索所有其他消息,WM_MOUSEWHEEL就是其中之一。这很好地模拟了Windows 10中鼠标滚轮的新默认行为。对的调用仅对键盘输入消息有意义。您不需要在
WM\u mouseweel
处理程序中调用它。还请注意,当应用程序进入模式循环时(最明显的是,打开模式对话框时),此代码就会失败。如果您没有自己的消息泵(即,如果您使用DialogBoxParam),此解决方案会容易得多。@DavidGausmann:这几乎不容易。您必须为每个子控件创建子类,才能使其正常工作。你错过了一个,它以非常微妙的方式断裂。并不是说你会有很多选择,但这肯定不容易。如果你没有自己的消息泵(即,如果你使用DialogBoxParam),这个解决方案会容易得多。@DavidGausmann:这几乎不容易。您必须为每个子控件创建子类,才能使其正常工作。你错过了一个,它以非常微妙的方式断裂。并不是说你会有很多选择,但这肯定不容易。感谢发布此解决方案-正如你所说,这比以前发布的解决方案简单得多。感谢发布此解决方案-正如你所说,这比以前发布的解决方案简单得多。