在this的帮助下从this继续,我有以下代码,它是自定义容器窗口类的一部分,应该将其父级作为其背景,以伪造透明度:< / p>
static HBRUSH getControlBackgroundBrush(HWND hwnd, HDC dc, RECT *hwndScreenRect)
{
HWND parent;
RECT parentRect;
int class;
HDC cdc;
HBITMAP bitmap, prevbitmap;
HBRUSH brush;
parent = hwnd;
for (;;) {
parent = GetAncestor(parent, GA_PARENT);
// skip groupboxes; they're (supposed to be) transparent
// skip nested containers; they don't draw anything
// note: returns 0 if parent's class is L"button", 1 if containerClass, -1 if neither
class = windowClassOf(parent, L"button", containerClass, NULL);
if (class != 0 && class != 1)
break;
}
if (GetClientRect(parent, &parentRect) == 0)
logLastError("error getting parent's client rect in getControlBackgroundBrush()");
cdc = CreateCompatibleDC(dc);
if (cdc == NULL)
logLastError("error creating compatible DC in getControlBackgroundBrush()");
bitmap = CreateCompatibleBitmap(dc, parentRect.right - parentRect.left, parentRect.bottom - parentRect.top);
if (bitmap == NULL)
logLastError("error creating compatible bitmap in getControlBackgroundBrush()");
prevbitmap = SelectObject(cdc, bitmap);
if (prevbitmap == NULL)
logLastError("error selecting bitmap into compatible DC in getControlBackgroundBrush()");
SendMessageW(parent, WM_PRINTCLIENT, (WPARAM) cdc, PRF_CLIENT);
// create it now, just to be safe
brush = CreatePatternBrush(bitmap);
if (brush == NULL)
logLastError("error creating pattern brush in getControlBackgroundBrush()");
if (SelectObject(cdc, prevbitmap) != bitmap)
logLastError("error selecting previous bitmap back into compatible DC in getControlBackgroundBrush()");
if (DeleteObject(bitmap) == 0)
logLastError("error deleting compatible bitmap in getControlBackgroundBrush()");
if (DeleteDC(cdc) == 0)
logLastError("error deleting compatible DC in getControlBackgroundBrush()");
// the given control rect is in screen coordinates; convert to parent coordinates
MapWindowRect(NULL, parent, hwndScreenRect);
if (SetBrushOrgEx(dc, -hwndScreenRect->left, -hwndScreenRect->top, NULL) == 0)
logLastError("error setting brush origin in getControlBackgroundBrush()");
return brush;
}
// TODO this doesn't work right for partial redraws
static void paintContainerBackground(HWND hwnd, HDC dc, RECT *paintRect)
{
RECT screenRect;
HBRUSH brush, prevbrush;
// getControlBackgroundBrush() needs a screen rectangle
screenRect = *paintRect;
MapWindowRect(hwnd, NULL, &screenRect);
brush = getControlBackgroundBrush(hwnd, dc, &screenRect);
prevbrush = SelectObject(dc, brush);
if (prevbrush == NULL)
logLastError("error selecting background brush into DC in paintContainerBackground()");
if (PatBlt(dc, paintRect->left, paintRect->top, paintRect->right - paintRect->left, paintRect->bottom - paintRect->top, PATCOPY) == 0)
logLastError("error drawing container background in paintContainerBackground()");
if (SelectObject(dc, prevbrush) != brush)
logLastError("error selecting previous brush back into DC in paintContainerBackground()");
if (DeleteObject(brush) == 0)
logLastError("error deleting background brush in paintContainerBackground()");
}
// window procedure
case WM_PAINT:
if (cc == NULL)
break;
c = (struct container *) (uiControl(cc)->Internal);
dc = BeginPaint(c->hwnd, &ps);
if (dc == NULL)
logLastError("error beginning container paint in containerWndProc()");
r = ps.rcPaint;
paintContainerBackground(c->hwnd, dc, &r);
EndPaint(c->hwnd, &ps);
return 0;
在这个容器类的父库的测试程序中,我有一行按钮和另一个按钮来隐藏它们。隐藏移动隐藏的按钮;显示将其移回。
抢先注意:下面的屏幕截图使用Windows XP作为渐变,其选项卡控件用作背景,非常适合测试上面的代码并演示像我一直在询问的错误。
现在,如果我理解正确,那么两个MapWindowRect()
调用会将给定的客户端rect部分转换为父客户端矩形坐标,因此SetBrushOrgEx()
将设置将原点刷到给定客户端rect部分的左上角,PatBlt()
将在真正的左上角绘制它。
当绘制整个容器时,这似乎工作正常。
但是当我隐藏按钮行时,更新rect比整个客户端rect小。而不是绘制背景的正确部分,而是获得其他背景:
取决于窗户的高度;在这种情况下,窗口有点高,因此矩形不可见;如果窗口较短,它将是白色的(显然靠近背景的顶部)。
现在,如果我完全忽略更新rect和客户端 - &gt;屏幕转换,直接使用窗口rect:
GetWindowRect(hwnd, hwndScreenRect);
// the given control rect is in screen coordinates; convert to parent coordinates
MapWindowRect(NULL, parent, hwndScreenRect);
if (SetBrushOrgEx(dc, -hwndScreenRect->left, -hwndScreenRect->top, NULL) == 0)
logLastError("error setting brush origin in getControlBackgroundBrush()");
然后的所有内容似乎都正常工作:
那么:我对MapWindowRect()
,SetBrushOrgEx()
和PatBlt()
导致第一个代码不能正常工作的方式有什么误解?为什么第二个代码有效?鉴于我对一切应该如何运作的想法,它不应该......
感谢。 (希望这一切都在不清楚的情况下完成。)