【问题标题】:WindowFromPoint doesn't trigger WM_NCHITTEST when window is being dragged拖动窗口时,WindowFromPoint 不会触发 WM_NCHITTEST
【发布时间】:2021-08-08 14:03:06
【问题描述】:

我正在尝试按照this 回答中提供的说明,以便在当前被拖动的窗口旁边找到某个点下方的窗口。

我尝试的问题是在拖动操作期间调用WindowFromPoint 时,WM_NCHITTEST 消息显然没有被触发。所以整个事情都不起作用,我无法获得被拖动的窗口下方的窗口。

这是一个最小的可重现示例。如果您运行此程序并通过标题栏拖动其中一个窗口,您会注意到“OnNcHitTest”不会显示在调试控制台中,即使正在处理 WM_WINDOWPOSCHANGED 并且正在调用 WindowFromPoint

#include <windows.h>
#include <atlbase.h>
#include <atlwin.h>
#include <atltypes.h>

using namespace ATL;

class CMyWindow :
    public CWindowImpl<CMyWindow, CWindow, CWinTraits<WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, WS_EX_TOOLWINDOW>>
{
public:
    CMyWindow() : m_fDragging(FALSE)
    {
    }

BEGIN_MSG_MAP(CMyWindow)
    MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged)
    MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
    MESSAGE_HANDLER(WM_EXITSIZEMOVE, OnExitSizeMove)
    MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand)
    COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnClickedCancel)
END_MSG_MAP()

private:
    LRESULT OnSysCommand(UINT, WPARAM wParam, LPARAM, BOOL& bHandled)
    {
        bHandled = FALSE;

        if ((wParam & 0xFFF0) == SC_MOVE)
        {
            m_fDragging = TRUE;
            ATLTRACE(L"\nDrag begin\n");
        }
            
        return 0;
    }

    LRESULT OnExitSizeMove(UINT, WPARAM, LPARAM, BOOL& bHandled)
    {
        bHandled = FALSE;
        
        m_fDragging = FALSE;
        ATLTRACE(L"\nDrag end\n");
        
        return 0;
    }

    LRESULT OnNcHitTest(UINT, WPARAM, LPARAM, BOOL& bHandled)
    {
        ATLTRACE(L"\nOnNcHitTest\n");
        
        if (m_fDragging)
            return HTTRANSPARENT;

        bHandled = FALSE;
        return 0;
    }

    LRESULT OnWindowPosChanged(UINT, WPARAM, LPARAM, BOOL& bHandled)
    {
        ATLTRACE(L"\nOnWindowPosChanged\n");
        
        bHandled = FALSE;

        if (m_fDragging)
        {
            CPoint pt;
            if (GetCursorPos(&pt))
            {
                ATLTRACE(L"\nCalling WindowFromPoint\n");
                HWND hwndFromPoint = WindowFromPoint(pt);
            }
        }

        return 0;
    }

    LRESULT OnClickedCancel(WORD, WORD, HWND, BOOL&)
    {
        DestroyWindow();
        return 0;
    }

    void OnFinalMessage(HWND)
    {
        delete this;
    }

    BOOL m_fDragging;
};

INT APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, INT)
{
    for (UINT i = 0; i < 3; ++i)
    {
        CMyWindow* pwnd = new CMyWindow();
        if (pwnd)
        {
            CRect rc(0, 0, 500, 500);
            if (pwnd->Create(NULL, &rc))
            {
                pwnd->CenterWindow(NULL);
                pwnd->ShowWindow(SW_SHOW);
            }
        }
    }

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (INT)msg.wParam;
}

谁能解释我做错了什么?这是否与移动/大小模态循环或其他什么有关?我认为这不是问题所在,因为只要WM_WINDOWPOSCHANGED 被触发并且WindowFromPoint 被调用,那么我认为WM_NCHITTEST 就会被发送。但也许我错了。

或者问题是否与鼠标位于非客户区有关?

感谢您的帮助。

【问题讨论】:

  • 坦率地说,我不明白为什么被拖动的窗口会被发送WM_NCHITTEST 消息......显然,结果将是HTCAPTION,否则它不会被拖动。跨度>
  • 那么链接的答案应该如何工作?
  • 等待作者解答...

标签: c++ winapi drag-and-drop


【解决方案1】:

我在OnNcHitTest 中进行了更改,以允许拖动客户区中的任意点:

LRESULT OnNcHitTest(UINT, WPARAM, LPARAM, BOOL& bHandled)
{
    ATLTRACE(L"\nOnNcHitTest\n");

    if (m_fDragging)
        return HTTRANSPARENT;
    else
        return HTCAPTION;

    bHandled = FALSE;
    return 0;
}

现在OnNcHitTest在拖动过程中被调用如果你拖动除了标题之外的任何东西。你会得到不同的 HWND 句柄。不知道为什么会有差异。

您到底想达到什么目的?自定义拖放?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-06
    • 1970-01-01
    • 2020-01-16
    • 1970-01-01
    • 2013-01-05
    • 1970-01-01
    • 2017-03-22
    • 2013-08-05
    相关资源
    最近更新 更多