简体   繁体   中英

How do I properly move a window with a region?

I've just started looking into window regions, and I'm trying to create an elliptical window that I can move by dragging the client area. Unfortunately, when I drag the window, the window flashes back and forth from the ellipse to the normal window (as if I never called SetWindowRgn ), and back, repeatedly and rapidly.

I read on MSDN that I have to call SetWindowRgn(nullptr); , then move the window, then reset the region, which I have already done in my code. I move the window by calling SetWindowPos with SWP_NOZORDER , SWP_NOSIZE , and SWP_NOREDRAW , and I've tried adding on all of SWP_NOSENDCHANGING , SWP_DEFERERASE , and SWP_NOCOPYBITS as well, to no avail.

Here's my window procedure, with emphasis on WM_MOUSEMOVE . I know it won't work if I release the button outside of the window; I was planning to deal with that after this worked. I also left out error checking. It's pretty obvious that the calls do work, though, because the window does move as I drag it.

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    static bool moving{};

    switch (msg) {
        case WM_DESTROY: {
            PostQuitMessage(0);
            return 0;
        }

        case WM_LBUTTONDOWN: {
            moving = true;
            return 0;
        }

        case WM_LBUTTONUP: {
            moving = false;
            return 0;
        }

        case WM_MOUSEMOVE: {
            static POINT old{0, 0};

            if (moving) {
                RECT r;
                GetWindowRect(hwnd, &r);

                int x = GET_X_LPARAM(lParam);
                int y = GET_Y_LPARAM(lParam);

                RECT newPos;
                newPos.left = r.left + x - old.x;
                newPos.top = r.top + y - old.y;

                SetWindowRgn(hwnd, nullptr, FALSE);

                SetWindowPos(hwnd, nullptr, newPos.left, newPos.top, 0, 0,
                    SWP_NOZORDER | SWP_NOSIZE | SWP_NOREDRAW
                );

                SetWindowRgn(hwnd, CreateEllipticRgn(200, 200, 600, 400), FALSE);
            }

            old.x = GET_X_LPARAM(lParam);
            old.y = GET_Y_LPARAM(lParam);

            return 0;
        }
    }

    return DefWindowProc(hwnd, msg, wParam, lParam);
}

I've also tried calling ValidateRgn(hwnd, nullptr); at the end of WM_MOUSEMOVE , which doesn't change anything. As well, I've tried wrapping the DefWindowProc call in a condition that just returns 0 if moving is set in order to see whether it was just some other message being sent that was messing with it, but that resulted in the window doing nothing when dragged. I then applied that condition to WM_PAINT and WM_ERASEBKGND handlers, but that resulted in the same flickering problem when dragged.

In order to test it more easily, here's full code (just rudimentary window creation etc). Am I going about moving the window the right way? Is there some message or something that I should handle, but don't? This is happening on Window 7 Ultimate N.

A much easier way to handle the move logic is to handle the WM_NCHITTEST message, returning HTCAPTION . This makes Windows handle all the move logic for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM