Moving frameless window by dragging it from a portion of client area

∥☆過路亽.° 提交于 2020-04-11 04:21:07

问题


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;

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.


回答1:


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.

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;
    }
    // ...
}

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;
    }
    // ...
}

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)));



回答2:


You can call some magic code in WM_LBUTTONDOWN handler, AFAIR this:

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

I used this method a few years ago in Delphi and Windows XP. I think it must be similar for c++. Of course, you can check x and y before doing this.



来源:https://stackoverflow.com/questions/35522488/moving-frameless-window-by-dragging-it-from-a-portion-of-client-area

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!