我刚刚开始研究窗口区域,我正在尝试创建一个椭圆窗口,我可以通过拖动客户区来移动它。不幸的是,当我拖动窗口时,窗口从椭圆到普通窗口来回闪烁(好像我从未调用过SetWindowRgn
),然后反复快速地返回。
我在 MSDN 上读到我必须调用SetWindowRgn(nullptr);
,然后移动窗口,然后重置区域,这在我的代码中已经完成。我通过调用 、 和 来移动窗口SetWindowPos
,并且SWP_NOZORDER
我尝试添加所有、和,但无济于事。SWP_NOSIZE
SWP_NOREDRAW
SWP_NOSENDCHANGING
SWP_DEFERERASE
SWP_NOCOPYBITS
这是我的窗口过程,重点是WM_MOUSEMOVE
. 我知道如果我在窗口外释放按钮,它将不起作用;我打算在这工作之后处理这个问题。我也省略了错误检查。很明显,调用确实有效,因为窗口在我拖动时确实会移动。
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);
}
我也试过ValidateRgn(hwnd, nullptr);
在 结束时调用WM_MOUSEMOVE
,这并没有改变任何东西。同样,我尝试将DefWindowProc
调用包装在一个如果设置为仅返回 0 的条件中,moving
以查看是否只是正在发送的其他一些消息对其造成干扰,但这导致窗口在拖动时什么也不做。然后我将该条件应用于WM_PAINT
和WM_ERASEBKGND
处理程序,但是在拖动时会导致相同的闪烁问题。
为了更容易地测试它,这里是完整的代码(只是基本的窗口创建等)。我要以正确的方式移动窗户吗?是否有一些消息或我应该处理的东西,但没有?这发生在 Window 7 Ultimate N 上。