BeginDraw在状态栏上绘制-不遵守renderTarget的大小调整

问题描述

我有一个带窗口的Direct2D应用程序,并通过常用控件在窗口中添加了状态栏:

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

状态栏显示得很好,但是,尽管我定义了高度,但一旦我在消息循环中激活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);

我还创建了一个调整大小的函数

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

GetClientRect(windowHandle,&rectStatus);

rectRender.width = rectwindow.right;
rectRender.height = rectwindow.bottom - (rectStatus.bottom - rectStatus.top);
rendertarget->Resize(rectRender);
InvalidateRect(windowHandle,FALSE);

,并在WM_SIZING和WM_SIZE中调用

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

BeginDraw()是否不尊重rendertarget的尺寸并仅占据整个窗口?如果是这样,我应该考虑使用图层还是我的代码有问题?

编辑:对于这个问题,我收到了一些反对意见。如果我的帖子有问题,请告诉我,我会尽力改善。我在win32领域仍然很新鲜,但是我从这个平台中学到了很多。我很乐意为您提供有趣的问题和答案,但是简单的-1并不能为我提供改进的线索。我已经在MSDN和各种论坛上阅读了两个晚上的主题演讲,但没有发现我做错了什么。我试图通过编写说明问题的完整示例代码来尽可能地完善。

完整代码以供参考

#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,800,600,hInstance,NULL);
    if (!hWnd) return -1;

    HWND hStatus = CreateWindowEx(0,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,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,500.0f,100.0f);
        gfx->EndDraw();
    }
    return 0;
}

LRESULT CALLBACK WindowProc(HWND hWnd,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,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(),&rendertarget);
    if (res != S_OK) return false;

    res = rendertarget->CreateSolidColorBrush(D2D1::ColorF(1,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 r)
{
    brush->SetColor(D2D1::ColorF(1.0f,0.0f,1.0f));
    rendertarget->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(x,y),r,r),brush,1.0f);
}

解决方法

您可以将WS_CLIPCHILDREN窗口样式添加到MainWindow

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

或者,您可以创建另一个子窗口(同级到状态栏),并将其用于您的Direct2D目标。