通过从客户区域的一部分拖动无框窗口来移动它

use*_*858 2 c user-interface winapi custom-controls

正如标题所说,我想仅在用户将其从客户区的一部分拖动时才移动窗口.这将模仿正常的标题栏移动,这是因为我的表单是自定义的,它没有任何标题或标题栏.目前,我使用的代码如下:

...
case WM_NCHITTEST:
        return HTCAPTION;
Run Code Online (Sandbox Code Playgroud)

并且这可以使用户能够移动窗口,无论他在哪里拖动.我想限制这种可能性(只有窗口的顶部才允许移动).我没有尝试检查鼠标按下的位置,因为我不知道如何在WM_NCHITTEST消息中执行此操作.我在Visual Studio 2015中使用普通的Win32(winapi)C代码(目前没有MFC或其他任何东西).

我的自定义窗口

Cod*_*ray 6

你会遇到麻烦,如果你只是返回HTCAPTION响应的所有 WM_NCHITTEST消息.你会破坏滚动条,关闭按钮,调整边框大小等等,这些都是通过不同的HT*值实现的.

不过,你有正确的想法.你想让你的窗口的客户区可以拖动,所以你需要让Windows认为你的客户区实际上是标题区(正如你所知,它是可拖动的).该代码如下所示:

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    // ...
    case WM_NCHITTEST:
    {
        // Call the default window procedure for default handling.
        const LRESULT result = ::DefWindowProc(hWnd, uMsg, wParam, lParam);

        // You want to change HTCLIENT into HTCAPTION.
        // Everything else should be left alone.
        return (result == HTCLIENT) ? HTCAPTION : result;
    }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

但是,根据您问题中的图片,您似乎只想将其限制为窗口的某个区域.您需要准确定义该区域的内容,然后点击测试以查看用户是否已在该区域中单击.假设这rcDraggable是一个RECT包含图像中显示的红色框边界的结构(在屏幕坐标中),您可以使用以下代码:

static RECT rcDraggable = ...

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    // ...
    case WM_NCHITTEST:
    {
        // Call the default window procedure for default handling.
        const LRESULT result = ::DefWindowProc(hWnd, uMsg, wParam, lParam);

        // Get the location of the mouse click, which is packed into lParam.
        POINT pt;
        pt.x = GET_X_LPARAM(lParam);
        pt.y = GET_Y_LPARAM(lParam);

        // You want to change HTCLIENT into HTCAPTION for a certain rectangle, rcDraggable.
        // Everything else should be left alone.
        if ((result == HTCLIENT) && (PtInRect(&rcDraggable, pt))
        {
            return HTCAPTION;
        }
        return result;
    }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

如果您rcDraggable根据客户端坐标定义,则需要在执行命中测试之前将其转换为屏幕坐标以响应WM_NCHITTEST.为此,请调用该MapWindowPoints函数,如下所示:

RECT rc = rcDraggable;
MapWindowPoints(hWnd,   /* a handle to your window       */
                NULL,   /* convert to screen coordinates */
                reinterpret_cast<POINT*>(&rc),
                (sizeof(RECT) / sizeof(POINT)));
Run Code Online (Sandbox Code Playgroud)