启动时不显示 Direct2D DC 上下文呈现的图像

Direct2D DC context rendered images doesn't appear on startup

本文关键字:图像 上下文 DC 显示 Direct2D 启动      更新时间:2023-10-16

我具有带有本机Winapi窗口的简单应用程序,并且作为子窗口上的静态控制。我想用direct2d绘制子窗口。

绘图发生在WM_PAINT消息之外,因此我决定使用ID2D1DCRenderTarget。除了一件事外,一切都起作用。应用程序启动时我无法使图纸可见。

如果我在任何情况下都进行绘画(例如在WM_LBUTTONDOWN中),则图纸显示。但是,如果我在WM_CREATE中绘画,我在屏幕上看不到任何内容。

这是我的示例代码:

#include <iostream>
#include <windows.h>
#include <windowsx.h>
#include <d2d1.h>
#pragma comment(lib, "d2d1.lib")
HWND windowHandle = NULL;
HWND childWindowHandle = NULL;
ID2D1Factory* direct2DFactory = nullptr;
ID2D1DCRenderTarget* renderTarget = nullptr;
static void InitDirect2D ()
{
    D2D1CreateFactory (D2D1_FACTORY_TYPE_SINGLE_THREADED, &direct2DFactory);
    D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
        D2D1_RENDER_TARGET_TYPE_DEFAULT,
        D2D1::PixelFormat(
            DXGI_FORMAT_B8G8R8A8_UNORM,
            D2D1_ALPHA_MODE_IGNORE),
        0,
        0,
        D2D1_RENDER_TARGET_USAGE_NONE,
        D2D1_FEATURE_LEVEL_DEFAULT
        );
    direct2DFactory->CreateDCRenderTarget (&props, &renderTarget);
    renderTarget->SetAntialiasMode (D2D1_ANTIALIAS_MODE_ALIASED);
}
static void Paint ()
{
    ID2D1SolidColorBrush* blackBrush = nullptr;
    renderTarget->CreateSolidColorBrush (
        D2D1::ColorF (D2D1::ColorF::Black),
        &blackBrush
    );
    renderTarget->BeginDraw ();
    renderTarget->SetTransform (D2D1::Matrix3x2F::Identity ());
    renderTarget->Clear (D2D1::ColorF (D2D1::ColorF::LightGray));
    D2D1_RECT_F rect = D2D1::RectF (10.0f, 10.0f, 100.0f, 100.0f);
    renderTarget->DrawRectangle (&rect, blackBrush);
    renderTarget->EndDraw ();
}
static LRESULT CALLBACK ChildWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg) {
        case WM_CREATE:
            {
                RECT rc;
                GetClientRect (hwnd, &rc);
                renderTarget->BindDC (GetDC (hwnd), &rc);
                Paint ();
            }
            break;
        case WM_LBUTTONDOWN:
            Paint ();
            break;
        case WM_PAINT:
            break;
        case WM_SIZE:
            {
                RECT rc;
                GetClientRect (hwnd, &rc);
                renderTarget->BindDC (GetDC (hwnd), &rc);
                Paint ();
            }
            break;
        case WM_CLOSE:
            DestroyWindow (hwnd);
            break;
        case WM_DESTROY:
            PostQuitMessage (0);
            break;
            break;
    }
    LRESULT res = DefWindowProc (hwnd, msg, wParam, lParam);
    return res;
}
static void CreateChildWindow (HWND parentHandle)
{
    WNDCLASSEX windowClass;
    memset (&windowClass, 0, sizeof (WNDCLASSEX));
    windowClass.cbSize = sizeof(WNDCLASSEX);
    windowClass.style = 0;
    windowClass.lpfnWndProc = ChildWindowProc;
    windowClass.style = CS_DBLCLKS;
    windowClass.cbClsExtra = 0;
    windowClass.cbWndExtra = 0;
    windowClass.hInstance = NULL;
    windowClass.hCursor = LoadCursor (NULL, IDC_ARROW);
    windowClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
    windowClass.lpszMenuName = NULL;
    windowClass.lpszClassName = L"ChildWindowClass";
    RegisterClassEx (&windowClass);
    childWindowHandle = CreateWindowEx (
        0, windowClass.lpszClassName, L"", WS_CHILD,
        CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, parentHandle, NULL, NULL, nullptr
    );
    ShowWindow (childWindowHandle, SW_SHOW);
    UpdateWindow (childWindowHandle);
    MoveWindow (childWindowHandle, 10, 10, 780, 580, TRUE);
}
static LRESULT CALLBACK MainWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    if (msg == WM_CREATE) {
        CreateChildWindow (hwnd);
        InvalidateRect (hwnd, NULL, FALSE);
    }
    switch (msg) {
        case WM_SIZE:
            {
                int newWidth = LOWORD (lParam);
                int newHeight = HIWORD (lParam);
                MoveWindow (childWindowHandle, 10, 10, newWidth - 20, newHeight - 20, TRUE);
            }
            break;
        case WM_CLOSE:
            DestroyWindow (hwnd);
            break;
        case WM_DESTROY:
            PostQuitMessage (0);
            break;
    }
    return DefWindowProc (hwnd, msg, wParam, lParam);
}
static int CreateMainWindow ()
{
    WNDCLASSEX windowClass;
    memset (&windowClass, 0, sizeof (WNDCLASSEX));
    windowClass.cbSize = sizeof (WNDCLASSEX);
    windowClass.style = 0;
    windowClass.lpfnWndProc = MainWindowProc;
    windowClass.style = CS_DBLCLKS;
    windowClass.cbClsExtra = 0;
    windowClass.cbWndExtra = 0;
    windowClass.hInstance = NULL;
    windowClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    windowClass.hCursor = LoadCursor (NULL, IDC_ARROW);
    windowClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
    windowClass.lpszMenuName = NULL;
    windowClass.lpszClassName = L"WindowClass";
    windowClass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    RegisterClassEx (&windowClass);
    RECT requiredRect = { 0, 0, 800, 600 };
    HWND windowHandle = CreateWindowEx (
        WS_EX_WINDOWEDGE, windowClass.lpszClassName, L"Example", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, requiredRect.right - requiredRect.left, requiredRect.bottom - requiredRect.top, NULL, NULL, NULL, nullptr
    );
    if (windowHandle == NULL) {
        return 1;
    }
    ShowWindow (windowHandle, SW_SHOW);
    UpdateWindow (windowHandle);
    MSG msg;
    while (GetMessage (&msg, NULL, 0, 0)) {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
    return 0;
}
int main (int argc, char* argv[])
{
    InitDirect2D ();
    return CreateMainWindow ();
}

您是否知道如何使图纸在应用程序启动中可见?

WM_CREATE窗口中尚未完整创建尚未创建,因此绘画不起作用。您应该编写适当的WM_PAINT(和WM_ERASEBKGND)消息处理程序,然后在那里执行所有绘画操作。然后,当您需要重新绘制作为对任何其他消息的响应(例如WM_LBUTTONDOWN)时,您需要无效窗口并触发WM_PAINT,而不是立即调用Paint();