通过从客户区

时间:2016-02-20 11:19:51

标签: c user-interface winapi custom-controls

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

...
case WM_NCHITTEST:
        return HTCAPTION;

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

My custom window

2 个答案:

答案 0 :(得分: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;
    }
    // ...
}

但是,根据您问题中的图片,您似乎希望将此限制仅限于窗口的某个区域。您需要准确定义该区域的内容,然后点击测试以查看用户是否已在该区域中单击。假设rcDraggable是包含the red box shown in your image边界的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;
    }
    // ...
}

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

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

答案 1 :(得分:1)

你可以在WM_LBUTTONDOWN处理程序中调用一些魔术代码,AFAIR:

 ReleaseCapture();
 SendMessage(yourWindowHandle, WM_SYSCOMMAND, 0xf012, 0) ;

几年前我在Delphi和Windows XP中使用过这种方法。我认为c ++必须类似。当然,在执行此操作之前,您可以检查x和y。