通过从客户区域的一部分拖动移动无框架窗口 [英] Moving frameless window by dragging it from a portion of client area

查看:100
本文介绍了通过从客户区域的一部分拖动移动无框架窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如标题所述,仅当用户将其从客户区的一部分拖动时,我才想移动窗口。这将是对正常标题栏运动的模仿,这是因为我的表单是自定义的,并且没有任何标题或标题栏。此刻,我使用以下代码:

As the title says, I would like to move the window only when the user will drag it from a portion of the client area. This will be an imitation of the normal caption bar movement and it's because my form is custom and it doesn't have any title or caption bars. At the moment, I use the code as follows:

...
case WM_NCHITTEST:
        return HTCAPTION;

效果很好,无论用户从何处拖动都可以使窗口移动。我想限制这种可能性(仅窗口顶部允许移动)。我没有尝试检查按下过的鼠标的位置,因为我不知道如何在 WM_NCHITTEST 消息中进行操作。
我在Visual Studio 2015中使用普通的Win32(winapi)C代码(目前没有MFC或其他任何工具)。

and that works fine for making the user able to move the window no matter where he drags from. I would like to limit this possibility (only the top of the window will allow movement). I haven't tried checking the position of the mouse pressed because I don't know how to do it in the WM_NCHITTEST message. I use plain Win32 (winapi) C code (no MFC or anything else at the moment) in Visual Studio 2015.

推荐答案

如果只返回 HTCAPTION 响应 all WM_NCHITTEST 消息。您将破坏滚动条,关闭按钮,调整边框大小等内容,这些都是通过不同的 HT * 值实现的。

You will run into trouble if you just return HTCAPTION in response to all WM_NCHITTEST messages. You will break things like scrollbars, close buttons, resizing borders, etc. that are all implemented via different HT* values.

不过,您的想法正确。您希望使窗口的客户区域可拖动,因此您需要诱使Windows认为您的客户区域实际上是标题区域(如您所知,它是可拖动的)。该代码如下所示:

You have the right idea, though. You want to make the client area of your window draggable, so you need to trick Windows into thinking that your client area is actually the caption area (which, as you know, is draggable). That code looks like this:

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 是一个 RECT 结构,其中包含图像中显示的红色框(在屏幕坐标中),您可以使用以下代码:

However, based on the image in your question, you appear to want to restrict this to only a certain region of your window. You will need to define exactly what that area is, and then hit-test to see if the user has clicked in that area. Assuming that rcDraggable is a RECT structure that contains the bounds of the red box shown in your image (in screen coordinates), you can use the following code:

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 函数,如下所示:

If you define rcDraggable in terms of client coordinates, you will need to convert it to screen coordinates before doing the hit-testing in response to WM_NCHITTEST. To do that, call the MapWindowPoints function, like so:

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

这篇关于通过从客户区域的一部分拖动移动无框架窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆