简体   繁体   English

BeginDraw() 在状态栏上绘制 - 不考虑调整 renderTarget 的大小

[英]BeginDraw() paints over statusbar - resizing of renderTarget not respected

I have a windowed Direct2D app and added a statusbar to the window from common controls:我有一个窗口化的 Direct2D 应用程序,并从常用控件向窗口添加了一个状态栏:

InitCommonControls();
HWND hStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL,
        WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0,
        hWnd, (HMENU)ID_STATUSBAR, GetModuleHandle(NULL), NULL);

The statusbar is showing up just fine, but as soon as I activate the BeginDraw() & EndDRaw() functions in my message loop, the statusbar is painted over, despite the fact I defined the height of the renderTarget when initialising it状态栏显示得很好,但是一旦我在我的消息循环中激活了BeginDraw()EndDRaw()函数,状态栏就会被绘制出来,尽管我在初始化时定义了renderTarget的高度

res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory);

GetClientRect(windowHandle, &rectWindow);
GetClientRect(statusHandle, &rectStatus);
rectRender.width = rectWindow.right;
rectRender.height = rectWindow.bottom - (rectStatus.bottom - rectStatus.top);

res = factory->CreateHwndRenderTarget(
    D2D1::RenderTargetProperties(),
    D2D1::HwndRenderTargetProperties(windowHandle, rectRender),
    &renderTarget);

I also created a resize function我还创建了一个调整大小功能

RECT rectWindow{ 0 }, rectStatus{ 0 };
D2D1_SIZE_U rectRender{ 0 };

GetClientRect(windowHandle, &rectWindow);
GetClientRect(statusHandle, &rectStatus);

rectRender.width = rectWindow.right;
rectRender.height = rectWindow.bottom - (rectStatus.bottom - rectStatus.top);
renderTarget->Resize(rectRender);
InvalidateRect(windowHandle, NULL, FALSE);

and called in in WM_SIZING and WM_SIZE:并呼吁在WM_SIZING和WM_SIZE:

case WM_SIZE:
case WM_SIZING:
    hStatus = GetDlgItem(hWnd, ID_STATUSBAR);
    gfx->Resize(hWnd, hStatus);
    SendMessage(hStatus, WM_SIZE, 0, 0);

Doesn't BeginDraw() respect the dimensions of the rendertarget and just take the entire window? BeginDraw()尊重BeginDraw()的尺寸并只占用整个窗口吗? And if so, should I consider using layers or is there something wrong in my code?如果是这样,我应该考虑使用层还是我的代码有问题?

EDIT: I received some downvotes for this question.编辑:我收到了一些反对这个问题的票。 If there's something wrong with my post, do let me know and I'll try to improve.如果我的帖子有问题,请告诉我,我会努力改进。 I'm still fresh in the win32 world, but I've learned a lot from this platform.我对 win32 世界还很陌生,但我从这个平台上学到了很多东西。 I would love to contribute with interesting questions and answers, but a simple -1 doesn't give me a clue what to improve.我很乐意提供有趣的问题和答案,但是一个简单的 -1 并没有给我提供改进的线索。 I've read 2 evenings about the subject on MSDN and various forums but didn't see what I do wrong.我已经在 MSDN 和各种论坛上阅读了 2 个晚上的主题,但没有看到我做错了什么。 I tried be as complete as possible by writing an complete example code that illustrates the issue.我尝试通过编写说明问题的完整示例代码来尽可能完整。

For reference the entire code供参考整个代码

#include <windows.h>
#include <CommCtrl.h>
#include <d2d1.h>

#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "d2d1.lib")

#define ID_STATUSBAR 1000

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

class Graphics
{
    ID2D1Factory* factory;
    ID2D1HwndRenderTarget* renderTarget;
    ID2D1SolidColorBrush* brush;

public:
    Graphics()
    {
        factory = NULL;
        renderTarget = NULL;
        brush = NULL;
    }
    ~Graphics()
    {
        if (factory) factory->Release();
        if (renderTarget) renderTarget->Release();
        if (brush) brush->Release();
    }
    bool Init(HWND windowHandle, HWND statusHandle);
    void BeginDraw() { renderTarget->BeginDraw(); }
    void EndDraw() { renderTarget->EndDraw(); }
    void Resize(HWND windowHandle, HWND statusHandle);
    void DrawCircle(float x, float y, float r);
};

HINSTANCE hInstance;
Graphics* gfx;

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
    InitCommonControls();

    WNDCLASS wc = { };
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = TEXT("mainwindow");
    RegisterClass(&wc);

    HWND hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, TEXT("mainwindow"),
        TEXT("MainWindow"), WS_OVERLAPPEDWINDOW, 100, 100, 800, 600,
        NULL, NULL, hInstance, NULL);
    if (!hWnd) return -1;

    HWND hStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL,
        WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0,
        hWnd, (HMENU)ID_STATUSBAR, GetModuleHandle(NULL), NULL);

    gfx = new Graphics;
    if (!gfx->Init(hWnd, hStatus))
    {
        delete gfx;
        return -1;
    }

    ShowWindow(hWnd, nCmdShow);

    MSG message{ 0 };
    bool runGame = true;

    while (runGame)
    {
        while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&message);
            DispatchMessage(&message);

            if (message.message == WM_QUIT)
                runGame = false;
        }
        gfx->BeginDraw();
        gfx->DrawCircle(400.0f, 100.0f, 100.0f);
        gfx->DrawCircle(400.0f, 300.0f, 100.0f);
        gfx->DrawCircle(400.0f, 500.0f, 100.0f);
        gfx->EndDraw();
    }
    return 0;
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HWND hStatus;

    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_SIZE:
    case WM_SIZING:
        hStatus = GetDlgItem(hWnd, ID_STATUSBAR);
        gfx->Resize(hWnd, hStatus);
        SendMessage(hStatus, WM_SIZE, 0, 0);
        return 0;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

bool Graphics::Init(HWND windowHandle, HWND statusHandle)
{
    RECT rectWindow{ 0 }, rectStatus{ 0 };
    D2D1_SIZE_U rectRender{ 0 };

    HRESULT res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory);
    if (res != S_OK) return false;

    GetClientRect(windowHandle, &rectWindow);
    GetClientRect(statusHandle, &rectStatus);
    rectRender.width = rectWindow.right;
    rectRender.height = rectWindow.bottom - (rectStatus.bottom - rectStatus.top);

    res = factory->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(),
        D2D1::HwndRenderTargetProperties(windowHandle, rectRender),
        &renderTarget);
    if (res != S_OK) return false;

    res = renderTarget->CreateSolidColorBrush(D2D1::ColorF(1, 0, 0, 0), &brush);
    if (res != S_OK) return false;

    return true;
}
void Graphics::Resize(HWND windowHandle, HWND statusHandle)
{
    if (renderTarget != NULL)
    {
        RECT rectWindow{ 0 }, rectStatus{ 0 };
        D2D1_SIZE_U rectRender{ 0 };

        GetClientRect(windowHandle, &rectWindow);
        GetClientRect(statusHandle, &rectStatus);

        rectRender.width = rectWindow.right;
        rectRender.height = rectWindow.bottom - (rectStatus.bottom - rectStatus.top);
        renderTarget->Resize(rectRender);
    }
}
void Graphics::DrawCircle(float x, float y, float r)
{
    brush->SetColor(D2D1::ColorF(1.0f, 0.0f, 0.0f, 1.0f));
    renderTarget->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(x, y), r, r), brush, 1.0f);
}

You can add WS_CLIPCHILDREN window style to your MainWindow :您可以将WS_CLIPCHILDREN窗口样式添加到MainWindow

HWND hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, TEXT("mainwindow"),
  TEXT("MainWindow"), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, 100, 100, 800, 600,
  NULL, NULL, hInstance, NULL);

Alternatively, you can create another child window (sibling to status bar) and use that for your Direct2D target.或者,您可以创建另一个子窗口(与状态栏同级)并将其用于Direct2D目标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM