C++ Visual Studio 2008 MFC无标题拖动对话框并检测所有鼠标事件

C++ Visual Studio 2008 MFC无标题拖动对话框并检测所有鼠标事件,c++,mfc,C++,Mfc,我被要求在现有程序中添加新功能。该程序由一个没有标题/边框的对话框组成。我需要两样东西: 当用户在对话框区域内单击时,只需将其关闭 当用户将鼠标移到对话框区域内并拖动时,移动对话框 以下是我到目前为止的发现: void MyDialog::onMessageReceived(UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_LBUTTONDOWN: lastX=LOWORD(lParam)

我被要求在现有程序中添加新功能。该程序由一个没有标题/边框的对话框组成。我需要两样东西:

  • 当用户在对话框区域内单击时,只需将其关闭
  • 当用户将鼠标移到对话框区域内并拖动时,移动对话框
  • 以下是我到目前为止的发现:

    void MyDialog::onMessageReceived(UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_LBUTTONDOWN:
            lastX=LOWORD(lParam);
            lastY=HIWORD(lParam);
            SendMessage(DlgHandle, WM_NCLBUTTONDOWN, HTCAPTION, NULL);
            break;
        case WM_LBUTTONUP:
            if (LOWORD(lParam)==lastX && HIWORD(lParam)==lastY)
                onKillButtonClick();
            break;
    }}
    
    编辑: 此函数的调用方式如下:

    INT_PTR CALLBACK MyDialog::dialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        _this->onMessageReceived(uMsg, wParam, lParam);
    } 
    
    移动窗口效果很好,但看起来WM_LBUTTONUP事件丢失了。我必须点击两下才能让它被解雇。 希望有人能帮我

    编辑:
    使用Spy++我看到WM_LBTTONUP被触发,但在新的WM_LBTTONUP发出后立即触发。

    首先,我同意Michael Walz的观点-这是一个非常令人困惑的行为:鼠标上升事件的处理取决于它是否移动。。。如果它移动了一点点呢?我宁愿用另一个动作来关闭这个对话框——点击图标,右键点击,等等

    但是,让用户移动无字幕窗口的正确方法是处理
    WM\u nchitest
    消息并返回
    HTCAPTION

    case WM_NCHITTEST:
        SetWindowLong(hDlg, DWL_MSGRESULT, HTCAPTION);
        return HTCAPTION;
    
    不幸的是,Windows将接管所有鼠标事件,因此,正如您所观察到的,您永远不会得到
    WM_LBUTTONUP
    。你可以选择设置一个短定时器,看看用户是否开始移动你的窗口;当您收到
    WM\u ENTERSIZEMOVE
    消息时取消它。如果计时器启动,关闭你的窗口。是的,这也很尴尬,但在你的提案中就没有了

    另一种方法是自己处理移动:

    static bool bDragging(false), bMoved(false);
    static POINT pt1 = {}, pt2 = {};
    static RECT r;
    switch (message)
    {
    case WM_LBUTTONDOWN:
        GetWindowRect(hDlg, &r);
        pt1 = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
        ClientToScreen(hDlg, &pt1);
        bDragging = true;
        bMoved = false;
        break;
    case WM_MOUSEMOVE:
        if (bDragging)
        {
            pt2 = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            ClientToScreen(hDlg, &pt2);
            if (pt2.x != pt1.x || pt2.y != pt1.y)
            {
                OffsetRect(&r, pt2.x - pt1.x, pt2.y - pt1.y);
                SetWindowPos(hDlg, 0, r.left, r.top, 0, 0, SWP_NOSIZE);
                pt1 = pt2;
                bMoved = true;
            }
        }
        break;
    case WM_LBUTTONUP:
        bDragging = false;
        if (!bMoved)
            PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0);
        bMoved = false;
        break;
    }
    return (INT_PTR)FALSE;
    

    我认为您移动对话框的方法并不完全正确,您应该考虑使用。我想WM_LBUTTONUP被你的WM_nbuttonDown黑客吃掉了。顺便说一句,你描述的交互对用户来说相当令人费解。如果我理解正确,当用户单击对话框然后释放按钮而不移动鼠标时,对话框将关闭,但当用户在释放按钮之前单击并移动鼠标时,窗口将移动。谢谢您的回答Michael,这正是我需要的行为。你知道有什么办法可以避免WM_LBUTTONUP被另一条信息“吃掉”吗?我或多或少地再现了你描述的行为,我没有任何解释。但你确定这种互动是好的吗?这似乎让我很困惑:单击并移动会移动对话框,单击而不移动会关闭对话框。此对话框表示计算机上打开了远程连接。它只显示一个关闭图标。用户可能希望通过单击这个小对话框来关闭连接,但是如果它覆盖了屏幕上一些有趣的部分,他也可能希望移动它