【发布时间】:2016-09-24 01:20:02
【问题描述】:
我一直在摆弄使用 Windows API 的自定义窗口。因此,我一直在使用扩展分层 Windows。我已经绘制了窗口,它可以工作。但是,在调整窗口大小时,调用 redraw/UpdateLayeredWindow(和 UpdateLayeredWindowIndirect)方法时会出现奇怪的闪烁/故障 [(Screenshot) ][1]。我在这里做错了什么吗?
void redrawBaseWindow(HWND window) {
RECT rect;
GetWindowRect(window, &rect);
int elipseDiam = ((rect.right - rect.left)+(rect.bottom-rect.top))/2*0.025;
HDC mainDC = GetDC(NULL);
POINT destination = { rect.left,rect.top };
POINT zero = destination;
SIZE size = { rect.right - rect.left,rect.bottom - rect.top };
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.AlphaFormat = 0;
bf.SourceConstantAlpha = 255;
HBRUSH brush = CreateSolidBrush(RGB(255, 0, 100));
HBRUSH oldbrush = SelectObject(mainDC, brush);
HPEN pen = CreatePen(PS_NULL, 0, RGB(0, 0, 0));
HPEN oldPen = SelectObject(mainDC, pen);
HBITMAP bmp = CreateCompatibleBitmap(mainDC, size.cx,size.cy);
HBITMAP oldBmp = SelectObject(mainDC, bmp);
FillRect(mainDC, &rect, CreateSolidBrush(RGB(0, 0, 0)));
Rectangle(mainDC, rect.left, rect.top + elipseDiam/2, rect.right, rect.bottom - elipseDiam/2);
Rectangle(mainDC, rect.left + elipseDiam/2, rect.top, rect.right - elipseDiam/2, rect.bottom);
UPDATELAYEREDWINDOWINFO updated = { sizeof(UPDATELAYEREDWINDOWINFO), NULL, &destination, &size, mainDC, &zero, RGB(0,0,0),&bf, ULW_COLORKEY, &rect};
UpdateLayeredWindowIndirect(window, &updated);
//BOOL error = UpdateLayeredWindow(window, NULL, &destination, &size, mainDC, &zero, RGB(0, 0, 0), &bf, ULW_COLORKEY);
SelectObject(mainDC, oldbrush);
SelectObject(mainDC, oldBmp);
SelectObject(mainDC, oldPen);
DeleteObject(brush);
DeleteObject(bmp);
DeleteObject(pen);
}
以防万一,Window Message Proc.
long __stdcall WndProc(HWND window, unsigned int msg, WPARAM wp, LPARAM lp) {
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = "Hello, World!";
RECT rect_window;
GetWindowRect(window, &rect_window);
switch (msg) {
case WM_SYSKEYDOWN:
MessageBeep(MB_ICONERROR);
case WM_CREATE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_NCHITTEST:;
int x = LOWORD(lp);
int y = HIWORD(lp);
if (x > rect_window.left && x<rect_window.right && y>rect_window.top && y < rect_window.top + 25)
return HTCAPTION;
if (x>=rect_window.left-3 && x<=rect_window.left+3)
return HTLEFT;
if (x >= rect_window.right - 3 && x <= rect_window.right + 3)
return HTRIGHT;
if (y >= rect_window.top - 3 && y <= rect_window.top + 3)
return HTTOP;
if (y >= rect_window.bottom - 3 && y <= rect_window.bottom + 3)
return HTBOTTOM;
break;
case WM_LBUTTONDOWN:
break;
case WM_SIZE:
redrawBaseWindow(window);
break;
case WM_PAINT:
break;
}
return DefWindowProc(window, msg, wp, lp);
}
编辑 2: 在 UpdateLayeredWindow 中使用 CreateCompatibleDC 值 [也不起作用]
void redrawBaseWindow(HWND window) {
RECT rect;
GetWindowRect(window, &rect);
int elipseDiam = ((rect.right - rect.left)+(rect.bottom-rect.top))/2*0.025;
HDC mainDC = GetDC(NULL);
HDC memDC = CreateCompatibleDC(mainDC);
POINT destination = { rect.left,rect.top };
POINT zero = destination;
SIZE size = { rect.right - rect.left,rect.bottom - rect.top };
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.AlphaFormat = 0;
bf.SourceConstantAlpha = 255;
HBRUSH brush = CreateSolidBrush(RGB(255, 0, 100));
HBRUSH oldbrush = SelectObject(memDC, brush);
HPEN pen = CreatePen(PS_NULL, 0, RGB(0, 0, 0));
HPEN oldPen = SelectObject(memDC, pen);
HBITMAP bmp = CreateCompatibleBitmap(memDC, size.cx,size.cy);
HBITMAP oldBmp = SelectObject(memDC, bmp);
FillRect(memDC, &rect, CreateSolidBrush(RGB(0, 0, 0)));
Rectangle(memDC, rect.left, rect.top + elipseDiam/2, rect.right, rect.bottom - elipseDiam/2);
Rectangle(memDC, rect.left + elipseDiam/2, rect.top, rect.right - elipseDiam/2, rect.bottom);
Ellipse(memDC, rect.left + elipseDiam, rect.top + elipseDiam, rect.left, rect.top); //Top-Left
Ellipse(memDC, rect.right - elipseDiam, rect.top, rect.right, rect.top + elipseDiam); //Top-Right
Ellipse(memDC, rect.left, rect.bottom, rect.left + elipseDiam, rect.bottom - elipseDiam); //Bottom-Left
Ellipse(memDC, rect.right - elipseDiam, rect.bottom, rect.right, rect.bottom - elipseDiam); //Bottom-Right
UPDATELAYEREDWINDOWINFO updated = { sizeof(UPDATELAYEREDWINDOWINFO), NULL, &destination, &size, memDC, &zero, RGB(0,0,0),&bf, ULW_COLORKEY, &rect};
UpdateLayeredWindowIndirect(window, &updated);
//BOOL error = UpdateLayeredWindow(window, NULL, &destination, &size, mainDC, &zero, RGB(0, 0, 0), &bf, ULW_COLORKEY);
SelectObject(memDC, oldbrush);
SelectObject(memDC, oldBmp);
SelectObject(memDC, oldPen);
DeleteObject(brush);
DeleteObject(bmp);
DeleteObject(pen);
ReleaseDC(NULL,mainDC);
ReleaseDC(NULL,memDC);
}
编辑 3:在 CreateCompatibleDC 设备上删除 DC,以及在屏幕 DC 而不是 CompatibleDC 上创建位图
void redrawBaseWindow(HWND window) {
RECT rect;
GetWindowRect(window, &rect);
int elipseDiam = ((rect.right - rect.left)+(rect.bottom-rect.top))/2*0.025;
HDC mainDC = GetDC(NULL);
HDC memDC = CreateCompatibleDC(mainDC);
POINT destination = { rect.left,rect.top };
POINT zero = destination;
SIZE size = { rect.right - rect.left,rect.bottom - rect.top };
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.AlphaFormat = 0;
bf.SourceConstantAlpha = 255;
HBRUSH brush = CreateSolidBrush(RGB(255, 0, 100));
HBRUSH oldbrush = SelectObject(memDC, brush);
HPEN pen = CreatePen(PS_NULL, 0, RGB(0, 0, 0));
HPEN oldPen = SelectObject(memDC, pen);
HBITMAP bmp = CreateCompatibleBitmap(mainDC, size.cx,size.cy);
HBITMAP oldBmp = SelectObject(memDC, bmp);
FillRect(memDC, &rect, CreateSolidBrush(RGB(0, 0, 0)));
Rectangle(memDC, rect.left, rect.top + elipseDiam/2, rect.right, rect.bottom - elipseDiam/2);
Rectangle(memDC, rect.left + elipseDiam/2, rect.top, rect.right - elipseDiam/2, rect.bottom);
Ellipse(memDC, rect.left + elipseDiam, rect.top + elipseDiam, rect.left, rect.top); //Top-Left
Ellipse(memDC, rect.right - elipseDiam, rect.top, rect.right, rect.top + elipseDiam); //Top-Right
Ellipse(memDC, rect.left, rect.bottom, rect.left + elipseDiam, rect.bottom - elipseDiam); //Bottom-Left
Ellipse(memDC, rect.right - elipseDiam, rect.bottom, rect.right, rect.bottom - elipseDiam); //Bottom-Right
UPDATELAYEREDWINDOWINFO updated = { sizeof(UPDATELAYEREDWINDOWINFO), NULL, &destination, &size, memDC, &zero, RGB(0,0,0),&bf, ULW_COLORKEY, &rect};
UpdateLayeredWindowIndirect(window, &updated);
//BOOL error = UpdateLayeredWindow(window, NULL, &destination, &size, mainDC, &zero, RGB(0, 0, 0), &bf, ULW_COLORKEY);
SelectObject(memDC, oldbrush);
SelectObject(memDC, oldBmp);
SelectObject(memDC, oldPen);
DeleteObject(brush);
DeleteObject(bmp);
DeleteObject(pen);
DeleteDC(memDC);
ReleaseDC(NULL,mainDC);
}
原始闪烁已修复。谢谢 [乔纳森·波塔] 然而发生了另一个错误:This
【问题讨论】:
-
请创建一个动画 gif 截图,我在您的图像上看不到问题。
-
会的,等会儿
-
在从
GetDC获得的 DC 中选择不同的位图有点奇怪,我不确定是否支持将屏幕的 DC 传递给UpdateLayeredWindow。正常用法是将您的位图选择到从CreateCompatibleDC获得的内存 DC 中,渲染到其中并从中更新窗口。您还有 GDI 资源泄漏(未调用ReleaseDC)。 -
在创建内存 DC 时,其中有一个单色位图,因此如果您在其上调用
CreateCompatibleBitmap,您最终也会得到一个单色位图。您需要与屏幕 DC 兼容的位图。此外,从CreateCompatibleDC获得的 DC 使用DeleteDC释放,而不是ReleaseDC。 -
请不要将答案编辑到您的问题中。而是发布答案(请参阅Can I answer my own question?)。如果您有新问题,请点击 按钮。