画笔原点,PatBlt()和MapWindowRect()混淆

时间:2015-05-06 01:48:26

标签: c winapi gdi

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小。而不是绘制背景的正确部分,而是获得其他背景:

Incorrect output

取决于窗户的高度;在这种情况下,窗口有点高,因此矩形不可见;如果窗口较短,它将是白色的(显然靠近背景的顶部)。

现在,如果我完全忽略更新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()");

然后的所有内容似乎都正常工作:

Correct output, or so it seems

那么:我对MapWindowRect()SetBrushOrgEx()PatBlt()导致第一个代码不能正常工作的方式有什么误解?为什么第二个代码有效?鉴于我对一切应该如何运作的想法,它不应该......

感谢。 (希望这一切都在不清楚的情况下完成。)

0 个答案:

没有答案