Direct2D使用WM_ERASEBKGND擦除背景吗?

问题描述 投票:0回答:1

似乎我已经学到了很难的方法,如果我们使用Direct2D进行绘画,那么一定不能使用WM_ERASEBKGND来进行背景擦除,但是我对此可能是错的,所以这里就是问题所在:

我使用空笔刷注册绘图窗口,以便让我手动处理背景擦除:

WNDCLASSEXW wcex;

wcex.hbrBackground = nullptr;
// etc...

这将使系统生成WM_ERASEBKGND,这是背景擦除的实现。效果很好:

// case WM_ERASEBKGND:
BOOL DrawableWindow::OnEraseBackground(WPARAM wParam)
{
    HRESULT hr = CreateGraphicsResources();

    if (SUCCEEDED(hr))
    {
        RECT rc{ };
        GetClientRect(mhWnd, &rc);
        const HDC hDC = reinterpret_cast<HDC>(wParam);

        // ID2D1DCRenderTarget
        hr = mpContextRender->BindDC(hDC, &rc);

        if (FAILED(hr))
        {
            DiscardGraphicsResources();
            return FALSE;
        }

        mpContextRender->BeginDraw();
        mpContextRender->Clear(mBackground); // D2D1::ColorF background color (ie. green)
        hr = mpContextRender->EndDraw();

        if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
        {
            DiscardGraphicsResources();
            return FALSE;
        }

        return TRUE;
    }

    // NOTE: Return value sets the PAINTSTRUCT.fErase
    // which the OnPaint() handler can use to determine if painting the backgound is needed
    return FALSE;
}

[确定,已经设置了背景,现在让我们在该背景上绘制!请参阅有条件删除背景的代码中的注释。

// case WM_PAINT:
void DrawableWindow::OnPaint()
{
    HRESULT hr = CreateGraphicsResources();

    if (SUCCEEDED(hr))
    {
        PAINTSTRUCT ps{ };

        BeginPaint(mhWnd, &ps);

        // ID2D1HwndRenderTarget
        mpWindowRender->BeginDraw();

        // ***THE PROBLEM IS HERE***
        // This value is nonzero if WM_ERASEBKGND erased the background!
        if (ps.fErase)
        {
            // We clear client area only if WM_ERASEBKGND returned FALSE!
            mpWindowRender->Clear(mBackground); // D2D1::ColorF background color (ie. green)
        }

        // We do drawing routuine here...
        // ...
        // done painting

        hr = mpWindowRender->EndDraw();

        if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
        {
            DiscardGraphicsResources();
        }

        EndPaint(mhWnd, &ps);
    }
}

[好吧,这不起作用,因为一旦调用BeginDraw(),背景就会变黑,而在WM_ERASEBKGND中删除的背景消失了!

if (ps.fErase)处理程序中的检查OnPaint()将不会执行,因为它是FALSE,这是错误的,因为已删除WM_ERASEBKGND内部的背景

结果是背景完全是黑色的,当我调整窗口大小时,我可以在几毫秒内看到我的原始背景,很快就会变成黑色和ofc。屏幕因色差而闪烁。

所以问题是,如何保留WM_ERASEBKGND中设置的背景?从FALSE返回WM_ERASEBKGND真的是这里唯一的解决方案吗?

那么WM_ERASEBKGND消息有什么意义?为什么BeginDraw()会忽略WM_ERASEBKGND中的背景,而将背景变成黑色?

其他图可见。只是背景丢失了。

c++ winapi directx
1个回答
2
投票

使用GDI的经典窗口渲染围绕着对单个图像缓冲区的增量更新。通常,重新绘制(部分透明)的窗口将需要确保对图像缓冲区的写入访问权限,剪切更新区域,请求父窗口绘制其背景,使该窗口绘制其背景,然后最终使该窗口绘制一些更新的内容。

与DirectX有所不同。通常,渲染至少是双重缓冲的。这些缓冲区的内容被交换而不是被复制。那就是上一帧(当前呈现)的内容在渲染时不可用,然后在交换缓冲区后被丢弃。因此,每次从头开始执行渲染,而将WM_ERASEBKGND的处理简化为什么都不做,仅返回TRUE表示背景已被擦除,因此我们不会重复此消息。

© www.soinside.com 2019 - 2024. All rights reserved.