Windows基础窗体编程

Direct2D基于Windows窗体,因此必须了解一些基本的Windows窗体编程:

首先,最基本的,可以使用Windows API写一个窗体:

View Code
#include 

typedef LRESULT (* message_callback)(HWND, WPARAM, LPARAM);

struct message_handler
{
    UINT message;
    message_callback handler;
};

static message_handler s_handlers[] = 
{
    {
        WM_PAINT, [] (HWND window, WPARAM, LPARAM) -> LRESULT
        {
            PAINTSTRUCT ps;
            BeginPaint(window, &ps);
            OutputDebugString(L"PAINT!\r\n");
            EndPaint(window, &ps);
            return 0;
        }
    }, 
    {
        WM_DESTROY, [] (HWND, WPARAM, LPARAM) -> LRESULT
        {
            PostQuitMessage(0);
            return 0;
        }
    }
};

int __stdcall wWinMain(HINSTANCE module, HINSTANCE, PWSTR, int)
{
    WNDCLASS wc = {};
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wc.hInstance = module;
    wc.lpszClassName = L"window";

    wc.lpfnWndProc = [] (HWND window, UINT message, WPARAM wparam, LPARAM lparam) -> LRESULT
    {
        for (auto h = s_handlers; h != s_handlers + _countof(s_handlers); ++h)
        {
            if (message == h->message)
            {
                return h->handler(window, wparam, lparam);
            }
        }

        return DefWindowProc(window, message, wparam, lparam);
    };

    RegisterClass(&wc);

    auto hwnd = CreateWindow(wc.lpszClassName, L"title", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
        nullptr, nullptr, module, nullptr);

    MSG message;
    BOOL result;
    
    while (result = GetMessage(&message, 0, 0, 0))
    {
        if (result != -1)
        {
            DispatchMessage(&message);
        }
    }
}

然后,加入ATL库后,窗体编程的事件过程可以简化很多: 

View Code
#include 
#include 
#include 

struct SampleWindow :
    CWindowImpl>
{
    DECLARE_WND_CLASS_EX(L"window", CS_HREDRAW | CS_VREDRAW, -1);
    BEGIN_MSG_MAP(SampleWindow)
        MESSAGE_HANDLER(WM_PAINT, PaintHandler)
        MESSAGE_HANDLER(WM_DESTROY, DestroyHandler)
    END_MSG_MAP()

    LRESULT PaintHandler(UINT, WPARAM, LPARAM, BOOL&)
    {
        PAINTSTRUCT ps;
        BeginPaint(&ps);
        EndPaint(&ps);
        return 0;
    }

    LRESULT DestroyHandler(UINT, WPARAM, LPARAM, BOOL&)
    {
        PostQuitMessage(0);
        return 0;
    }
};

int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    SampleWindow window;
    window.Create(nullptr, 0, L"Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE);

    MSG message;
    BOOL result;

    while (result = GetMessage(&message, 0, 0, 0))
    {
        if (result != -1)
        {
            DispatchMessage(&message);
        }
    }
}

要加入D2D1,需要引入COM组件,然而,COM比较复杂,微软引用WRL来简化COM的一些引用计数之类的操作,以下是一个基本的D2D1示例(显示一个带颜色的窗体):

View Code
#include "Precompiled.h"
#include 
#include 

#pragma comment(lib, "d2d1")

using namespace D2D1;
using namespace Microsoft::WRL;

struct SampleWindow
    : CWindowImpl>
{
    ComPtr m_factory;
    ComPtr m_target;

    DECLARE_WND_CLASS_EX(L"My D2D1 Window", CS_HREDRAW | CS_VREDRAW, -1);

    BEGIN_MSG_MAP(SampleWindow)
        MESSAGE_HANDLER(WM_PAINT, PaintHandler)
        MESSAGE_HANDLER(WM_DESTROY, DestroyHandler)
        MESSAGE_HANDLER(WM_SIZE, SizeHandler)
        MESSAGE_HANDLER(WM_DISPLAYCHANGE, DisplayChangeHandler)
    END_MSG_MAP()

    LRESULT DisplayChangeHandler(UINT, WPARAM, LPARAM, BOOL&)
    {
        Invalidate();
        return 0;
    }

    LRESULT SizeHandler(UINT, WPARAM, LPARAM lparam, BOOL&)
    {
        if (m_target)
        {
            if (m_target->Resize(SizeU(LOWORD(lparam), HIWORD(lparam))) != S_OK)
            {
                m_target.Reset();
            }
        }
        return 0;
    }

    LRESULT PaintHandler(UINT, WPARAM, LPARAM, BOOL&)
    {
        PAINTSTRUCT ps;
        VERIFY(BeginPaint(&ps));
        Render();
        EndPaint(&ps);
        return 0;
    }

    LRESULT DestroyHandler(UINT, WPARAM, LPARAM, BOOL&)
    {
        PostQuitMessage(0);
        return 0;
    }

    void Invalidate()
    {
        VERIFY(InvalidateRect(nullptr, false))
    }

    void Create()
    {
        D2D1_FACTORY_OPTIONS fo = {};
#ifdef DEBUG
        fo.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
#endif

        D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, 
                          fo, 
                          m_factory.GetAddressOf());
        CreateDeviceIndependentResources();
        VERIFY(__super::Create(nullptr, 0, L"title"));
    }

    void CreateDeviceIndependentResources()
    {
    }

    void CreateDeviceResources()
    {
    }

    void Render()
    {
        if (!m_target)
        {
            RECT rect;
            VERIFY(GetClientRect(&rect));

            auto size = SizeU(rect.right, rect.bottom);

            m_factory->CreateHwndRenderTarget(RenderTargetProperties(), 
                                              HwndRenderTargetProperties(m_hWnd, size), 
                                              m_target.GetAddressOf());
            CreateDeviceResources();
            
        }

        if (!(m_target->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED))
        {
            m_target->BeginDraw();

            Draw();

            if (m_target->EndDraw() == D2DERR_RECREATE_TARGET)
            {
                m_target.Reset();
            }
        }
    }

    void Draw()
    {
        m_target->Clear(ColorF(1.0f, 1.0f, 0.0f));
    }
};

int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    SampleWindow window;
    window.Create();

    MSG msg;
    BOOL result;
    while (result = GetMessage(&msg, 0, 0, 0))
    {
        if (result != -1)
        {
            DispatchMessage(&msg);
        }
    }
}

不得不说的是,这些示例和我原来在网上和书上看到的很不一样,感觉他写的更加优雅,通过他的讲解,可以很容易理解。

More content at http://pluralsight.com, Direct2D Fundamentals

你可能感兴趣的:(Windows基础窗体编程)