Windows基础窗体编程
Direct2D基于Windows窗体,因此必须了解一些基本的Windows窗体编程:
首先,最基本的,可以使用Windows API写一个窗体:
View Code
#include <Windows.h> 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 <Windows.h> #include <atlbase.h> #include <atlwin.h> struct SampleWindow : CWindowImpl<SampleWindow, CWindow, CWinTraits<WS_OVERLAPPEDWINDOW | WS_VISIBLE>> { 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 <d2d1.h> #include <wrl.h> #pragma comment(lib, "d2d1") using namespace D2D1; using namespace Microsoft::WRL; struct SampleWindow : CWindowImpl<SampleWindow, CWindow, CWinTraits<WS_OVERLAPPEDWINDOW | WS_VISIBLE>> { ComPtr<ID2D1Factory> m_factory; ComPtr<ID2D1HwndRenderTarget> 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