强制Win32通用控件使用"ID2D1HwndRenderTarget"? [英] Force Win32 common controls to draw on `ID2D1HwndRenderTarget`?

查看:77
本文介绍了强制Win32通用控件使用"ID2D1HwndRenderTarget"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 ID2D1HwndRenderTarget 绘制了大部分UI,但是我想要一些经典的窗口控件: button edit .如何

 <代码> ID2D1HwndRenderTarget * canvas = nullptr;//它是全局对象HWND按钮= nullptr;//它是全局对象HWND编辑= nullptr;//它是全局对象HWND custom = nullptr;//它是全局对象 

 <代码>//mainWindow WinPproc案例WM_CREATE:按钮= CreateWindowExW(0,L按钮",L发送",WS_CHILD | WS_VISIBLE,10、10、120、30,hWnd,BUTTON_ID,hInstance,0);//win32控件编辑= CreateWindowExW(0,L编辑",L编辑",WS_CHILD | WS_VISIBLE,10、50、120、30,hWnd,按钮ID,hInstance,0);//win32控件custom = CreateWindowExW(0,L"custom",L"Custom",WS_CHILD | WS_VISIBLE,10、90、120、30,hWnd,BUTTON_ID,hInstance,0);//这是我的自定义类休息;情况WM_PAINT:BeginPaint(hWnd,nullptr);render_target-> BeginPaint();... GUI渲染内容....HRESULT结果= render_target-> EndDraw();if(结果!= S_OK){//错误处理...}EndPaint(hWnd,nullptr);休息; 

 //自定义WinProc情况WM_PAINT:BeginPaint(hWnd,nullptr);render_target-> BeginPaint();...呈现东西...HRESULT结果= render_target-> EndDraw();if(结果!= S_OK){//错误处理...}EndPaint(hWnd,nullptr);休息; 

只有涂有 render_target 的东西才可见.我知道原因:因为 button edit 是默认的win32控件,它们是在内部使用 PAINTSTRUCT-> HDC 上下文绘制的.我阅读了

I draw most of my UI using ID2D1HwndRenderTarget, but I want some classic window controls: button, edit. How to

ID2D1HwndRenderTarget * canvas = nullptr; // it's global object
HWND button = nullptr; // it's global object
HWND edit = nullptr; // it's global object
HWND custom = nullptr; // it's global object

// mainWindow WinPproc
case WM_CREATE:
    button = CreateWindowExW(0, L"button", L"Send", WS_CHILD | WS_VISIBLE, 10, 10, 120, 30, hWnd, BUTTON_ID, hInstance, 0); // win32 control
    edit = CreateWindowExW(0, L"edit", L"Edit", WS_CHILD | WS_VISIBLE, 10, 50, 120, 30, hWnd, BUTTON_ID, hInstance, 0); // win32 control
    custom = CreateWindowExW(0, L"custom", L"Custom", WS_CHILD | WS_VISIBLE, 10, 90, 120, 30, hWnd, BUTTON_ID, hInstance, 0); // it's my custom class
    break;

case WM_PAINT:
    BeginPaint(hWnd, nullptr);
    render_target->BeginPaint();
    ... GUI rendering stuff ....
    HRESULT result = render_target->EndDraw();
    if(result != S_OK)
    {
       // Error handling
       ...
    }
    EndPaint(hWnd, nullptr);
    break;

// custom WinProc
case WM_PAINT:
    BeginPaint(hWnd, nullptr);
    render_target->BeginPaint();
    ... rendering stuff ....
    HRESULT result = render_target->EndDraw();
    if(result != S_OK)
    {
       // Error handling
       ...
    }
    EndPaint(hWnd, nullptr);
    break;

Only things painted with render_target are visible. I understand why: becausebutton and edit are default win32 controls, internally drawn using PAINTSTRUCT->HDC context. I read Direct2D and GDI Interoperability Overview and get the concept, but still don't know where this HDC intrecpet should take place? I don't want touch default control WM_PAINT. I have to supclass all default win32 controls?

How to force those Win32 controls to draw onto my render_target?

解决方案

If you want to share a device context (HDC) between GDI and Direct2D, you can use a ID2D1DCRenderTarget and Bind to this HDC when you want to render on it.

This is demonstrated in this official sample : GDI/Direct2D Interoperability Sample

Note, as is, it doesn't compile/work with today's Visual Studio. So, here is a similar code here with a simple button and textbox:

#include <windows.h>
#include <stdlib.h>
#include <math.h>
#include <d2d1.h>

template<class Interface>
inline void
SafeRelease(Interface** ppInterfaceToRelease)
{
    if (*ppInterfaceToRelease != NULL)
    {
        (*ppInterfaceToRelease)->Release();
        (*ppInterfaceToRelease) = NULL;
    }
}

EXTERN_C IMAGE_DOS_HEADER __ImageBase;

class DemoApp
{
public:
    DemoApp();
    ~DemoApp();

    HRESULT Initialize();

private:
    HRESULT CreateDeviceIndependentResources();
    HRESULT CreateDeviceResources();
    void DiscardDeviceResources();
    HRESULT OnRender(const PAINTSTRUCT& ps);
    static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

private:
    HWND m_hwnd;
    ID2D1Factory* m_pD2DFactory;
    ID2D1DCRenderTarget* m_pDCRT;
    ID2D1SolidColorBrush* m_pBlackBrush;
};

int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/)
{
    if (SUCCEEDED(CoInitialize(NULL)))
    {
        DemoApp app;
        if (SUCCEEDED(app.Initialize()))
        {
            MSG msg;
            while (GetMessage(&msg, NULL, 0, 0))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        CoUninitialize();
    }
    return 0;
}

DemoApp::DemoApp() :
    m_hwnd(NULL),
    m_pD2DFactory(NULL),
    m_pDCRT(NULL),
    m_pBlackBrush(NULL)
{
}

DemoApp::~DemoApp()
{
    SafeRelease(&m_pD2DFactory);
    SafeRelease(&m_pDCRT);
    SafeRelease(&m_pBlackBrush);
}

HRESULT DemoApp::Initialize()
{
    HRESULT hr;

    hr = CreateDeviceIndependentResources();
    if (SUCCEEDED(hr))
    {
        // Register the window class.
        WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
        wcex.style = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc = DemoApp::WndProc;
        wcex.cbClsExtra = 0;
        wcex.cbWndExtra = sizeof(LONG_PTR);
        wcex.hInstance = (HINSTANCE)&__ImageBase;
        wcex.hbrBackground = NULL;
        wcex.lpszMenuName = NULL;
        wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
        wcex.lpszClassName = L"D2DDemoApp";
        RegisterClassEx(&wcex);

        // Create the application window.
        // Because the CreateWindow function takes its size in pixels, we obtain the system DPI and use it to scale the window size.
        FLOAT dpiX, dpiY;
        m_pD2DFactory->GetDesktopDpi(&dpiX, &dpiY);

        m_hwnd = CreateWindow(
            L"D2DDemoApp",
            L"Direct2D Demo App",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            static_cast<UINT>(ceil(640.f * dpiX / 96.f)),
            static_cast<UINT>(ceil(480.f * dpiY / 96.f)),
            NULL,
            NULL,
            (HINSTANCE)&__ImageBase,
            this
        );

        hr = m_hwnd ? S_OK : E_FAIL;
        if (SUCCEEDED(hr))
        {
            ShowWindow(m_hwnd, SW_SHOWNORMAL);

            UpdateWindow(m_hwnd);
        }
    }

    return hr;
}

HRESULT DemoApp::CreateDeviceIndependentResources()
{
    // Create D2D factory
    return D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
}

HRESULT DemoApp::CreateDeviceResources()
{
    HRESULT hr = S_OK;
    if (!m_pDCRT)
    {
        // Create a DC render target.
        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
        );

        hr = m_pD2DFactory->CreateDCRenderTarget(&props, &m_pDCRT);
        if (SUCCEEDED(hr))
        {
            // Create a black brush.
            hr = m_pDCRT->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &m_pBlackBrush);
        }
    }

    return hr;
}

void DemoApp::DiscardDeviceResources()
{
    SafeRelease(&m_pDCRT);
    SafeRelease(&m_pBlackBrush);
}

HRESULT DemoApp::OnRender(const PAINTSTRUCT& ps)
{
    HRESULT hr;
    RECT rc;

    // Get the dimensions of the client drawing area.
    GetClientRect(m_hwnd, &rc);

    // Draw the pie chart with Direct2D.

    // Create the DC render target.
    hr = CreateDeviceResources();

    if (SUCCEEDED(hr))
    {
        // Bind the DC to the DC render target.
        hr = m_pDCRT->BindDC(ps.hdc, &rc);

        m_pDCRT->BeginDraw();
        m_pDCRT->SetTransform(D2D1::Matrix3x2F::Identity());
        m_pDCRT->Clear(D2D1::ColorF(D2D1::ColorF::White));

        m_pDCRT->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(150.0f, 150.0f), 100.0f, 100.0f), m_pBlackBrush, 3.0);

        m_pDCRT->DrawLine(
            D2D1::Point2F(150.0f, 150.0f),
            D2D1::Point2F((150.0f + 100.0f * 0.15425f), (150.0f - 100.0f * 0.988f)), m_pBlackBrush, 3.0
        );

        m_pDCRT->DrawLine(
            D2D1::Point2F(150.0f, 150.0f),
            D2D1::Point2F((150.0f + 100.0f * 0.525f), (150.0f + 100.0f * 0.8509f)), m_pBlackBrush, 3.0
        );

        m_pDCRT->DrawLine(
            D2D1::Point2F(150.0f, 150.0f),
            D2D1::Point2F((150.0f - 100.0f * 0.988f), (150.0f - 100.0f * 0.15425f)), m_pBlackBrush, 3.0
        );

        hr = m_pDCRT->EndDraw();

        if (SUCCEEDED(hr))
        {
            // Draw the pie chart with GDI.

            // Save the original object.
            HGDIOBJ original = NULL;
            original = SelectObject(ps.hdc, GetStockObject(DC_PEN));

            HPEN blackPen = CreatePen(PS_SOLID, 3, 0);
            SelectObject(ps.hdc, blackPen);

            Ellipse(ps.hdc, 300, 50, 500, 250);

            POINT pntArray1[2];
            pntArray1[0].x = 400;
            pntArray1[0].y = 150;
            pntArray1[1].x = static_cast<LONG>(400 + 100 * 0.15425);
            pntArray1[1].y = static_cast<LONG>(150 - 100 * 0.9885);

            POINT pntArray2[2];
            pntArray2[0].x = 400;
            pntArray2[0].y = 150;
            pntArray2[1].x = static_cast<LONG>(400 + 100 * 0.525);
            pntArray2[1].y = static_cast<LONG>(150 + 100 * 0.8509);


            POINT pntArray3[2];
            pntArray3[0].x = 400;
            pntArray3[0].y = 150;
            pntArray3[1].x = static_cast<LONG>(400 - 100 * 0.988);
            pntArray3[1].y = static_cast<LONG>(150 - 100 * 0.15425);

            Polyline(ps.hdc, pntArray1, 2);
            Polyline(ps.hdc, pntArray2, 2);
            Polyline(ps.hdc, pntArray3, 2);

            DeleteObject(blackPen);

            // Restore the original object.
            SelectObject(ps.hdc, original);
        }
    }

    if (hr == D2DERR_RECREATE_TARGET)
    {
        hr = S_OK;
        DiscardDeviceResources();
    }

    return hr;
}

LRESULT CALLBACK DemoApp::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message == WM_CREATE)
    {
        LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pcs->lpCreateParams);

        auto button = CreateWindowExW(0, L"button", L"Send", WS_CHILD | WS_VISIBLE, 10, 10, 120, 30, hwnd, (HMENU)1, (HINSTANCE)&__ImageBase, 0); // win32 control
        auto edit = CreateWindowExW(0, L"edit", L"Edit", WS_CHILD | WS_VISIBLE, 10, 50, 120, 30, hwnd, (HMENU)2, (HINSTANCE)&__ImageBase, 0); // win32 control
        return 1;
    }

    LRESULT result = 0;
    DemoApp* pDemoApp = (DemoApp*)(GetWindowLongPtr(hwnd, GWLP_USERDATA));
    bool wasHandled = false;
    if (pDemoApp)
    {
        switch (message)
        {
        case WM_PAINT:
        case WM_DISPLAYCHANGE:
        {
            PAINTSTRUCT ps;
            BeginPaint(hwnd, &ps);
            pDemoApp->OnRender(ps);
            EndPaint(hwnd, &ps);
        }
        result = 0;
        wasHandled = true;
        break;

        case WM_DESTROY:
        {
            PostQuitMessage(0);
        }
        result = 1;
        wasHandled = true;
        break;
        }
    }

    if (!wasHandled)
    {
        result = DefWindowProc(hwnd, message, wParam, lParam);
    }

    return result;
}

And here is how it renders (left circle is Direct2D, right is aliased GDI):

这篇关于强制Win32通用控件使用"ID2D1HwndRenderTarget"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆