WTL-Direct2D,DirectWrite,Windows Animation
2013-06-07 22:39
344 查看
WTL-Direct2D,DirectWrite,Windows Animation
Windows 7引入了不少有趣的新技术:Direct2D,DirectWrite,Windows Animation,还有Windows Media Foundation等等,在加上之前Windows Vista引入的Windows Image Component等技术,基本上把整个UI,多媒体框架都进行了翻新。这几天放假无事,在看ATL/WTL,也顺带关注下Windows 7引入的这些新API。看了下SDK Sample,在介绍Windows Animation时有个有趣的小例子叫AppDrive,当用鼠标点击窗口时,窗口的背景色会非常平滑的变色。代码逻辑本身比较简单,就是纯Win32的代码看得比较费劲。于是无聊将其用WTL改写了下,代码精简了不少。在写代码的过程中,越来越体会到ATL/WTL的强大,好用,可大大简化COM组件的编写和调用,非常适合进行Win32 API编程。下面就把实现代码直接贴出来啦。使用Windows Animation需要实现一个接口IUIAnimationManagerEventHandler,以下是这个接口的实现(与SDK Sample的实现方式不同):#pragma once #include "stdafx.h" #include <UIAnimation.h> [uuid("388E57E1-F20E-4E79-A732-35397AB8CC7C")] __interface IAnimationNotifyWindow : public IUnknown { HRESULT __stdcall SetNotifyWindow(HWND hNotifyWindow); }; class CAnimationEventHandler : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CAnimationEventHandler>, public IUIAnimationManagerEventHandler, public IAnimationNotifyWindow { public: BEGIN_COM_MAP(CAnimationEventHandler) COM_INTERFACE_ENTRY(IUIAnimationManagerEventHandler) COM_INTERFACE_ENTRY(IAnimationNotifyWindow) END_COM_MAP() //IUIAnimationManagerEventHandler method STDMETHOD(OnManagerStatusChanged)( UI_ANIMATION_MANAGER_STATUS newStatus, UI_ANIMATION_MANAGER_STATUS previousStatus) { if (m_NotifyWindow) m_NotifyWindow.Invalidate(); return S_OK; } //IAnimationNotifyWindow method STDMETHOD(SetNotifyWindow)(HWND hNotifyWindow) { ATLASSERT(::IsWindow(hNotifyWindow)); m_NotifyWindow = hNotifyWindow; return S_OK; } private: CWindow m_NotifyWindow; };这个CAnimationEventHandler类不仅实现了IUIAnimationManagerEventHandler,还实现了一个自定义接口IAnimationNotifyWindow,主窗口代码通过这个接口将其窗口句柄传递给CAnimationEventHandler类,以实现窗口通知(通知主窗口重绘)。主窗口实现代码:
#pragma once #include "stdafx.h" #include <cstdlib> #include <d2d1.h> #include <d2d1helper.h> #include <DWrite.h> #include <wincodec.h> #include <UIAnimation.h> #include "AnimationEventHandler.h" #pragma comment(lib,"d2d1.lib") #pragma comment(lib,"dwrite.lib") using D2D1::RenderTargetProperties; using D2D1::HwndRenderTargetProperties; using D2D1::LinearGradientBrushProperties; using D2D1::SizeU; using D2D1::SizeF; using D2D1::ColorF; using D2D1::Point2F; using D2D1::Point2U; using D2D1::RectF; using D2D1::Matrix3x2F; #pragma warning(push) #pragma warning(disable:4244) typedef CWinTraits<WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN> CMainWinTraits; class CMainWindow : public CWindowImpl<CMainWindow,CWindow,CMainWinTraits> { private: //Direct2D interfaces CComPtr<ID2D1Factory> m_spD2dFactory; CComPtr<ID2D1HwndRenderTarget> m_spHwndRT; CComPtr<ID2D1SolidColorBrush> m_spBkgndBrush; CComPtr<ID2D1LinearGradientBrush> m_spTextBrush; //DirectWrite interfaces CComPtr<IDWriteFactory> m_spDWriteFactory; CComPtr<IDWriteTextFormat> m_spTextFormat; //UIAnimation interfaces CComPtr<IUIAnimationManager> m_spIAniManager; CComPtr<IUIAnimationTimer> m_spIAniTimer; CComPtr<IUIAnimationTransitionLibrary> m_spIAniTransLib; CComPtr<IUIAnimationVariable> m_spIAniVarRed; //red CComPtr<IUIAnimationVariable> m_spIAniVarGreen; //greem CComPtr<IUIAnimationVariable> m_spIAniVarBlue; //blue public: DECLARE_WND_CLASS(_T("WTL main window")) BEGIN_MSG_MAP(CMainWindow) MSG_WM_LBUTTONDOWN(OnLButtonDown) MSG_WM_ERASEBKGND(OnEraseBkgnd) MSG_WM_CREATE(OnCreate) MSG_WM_DESTROY(OnDestroy) MSG_WM_PAINT(OnPaint) MSG_WM_SIZE(OnSize) END_MSG_MAP() int OnCreate(LPCREATESTRUCT lpCreateStruct) { SetWindowText(_T("Direct2D & DirectWrite & Windows Animation")); CreateDeviceIndependentResource(); CreateDeviceResource(); return 0; } void OnDestroy() { PostQuitMessage(0); } void OnPaint(CDCHandle) { UI_ANIMATION_SECONDS timeNow; IFR(m_spIAniTimer->GetTime(&timeNow)); IFR(m_spIAniManager->Update(timeNow)); Render(); UI_ANIMATION_MANAGER_STATUS status; m_spIAniManager->GetStatus(&status); if (status == UI_ANIMATION_MANAGER_BUSY) { Invalidate(FALSE); } } void OnSize(UINT nType, CSize size) { if (m_spHwndRT) m_spHwndRT->Resize(SizeU(size.cx,size.cy)); } BOOL OnEraseBkgnd(CDCHandle dc) { //We have ereased the background return TRUE; } void OnLButtonDown(UINT nFlags, CPoint point) { ChangeColor(); } private: void CreateDeviceIndependentResource() { //Direct2D IFR(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_spD2dFactory)); //DirectWrite IFR(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&m_spDWriteFactory))); //UIAnimation IFR(m_spIAniManager.CoCreateInstance(CLSID_UIAnimationManager)); IFR(m_spIAniTimer.CoCreateInstance(CLSID_UIAnimationTimer)); IFR(m_spIAniTransLib.CoCreateInstance(CLSID_UIAnimationTransitionLibrary)); CComPtr<IUIAnimationManagerEventHandler> spIAniEventHandler; IFR(CAnimationEventHandler::CreateInstance(&spIAniEventHandler)); CComPtr<IAnimationNotifyWindow> spIAniNotifyWindow; IFR(spIAniEventHandler->QueryInterface(&spIAniNotifyWindow)); spIAniNotifyWindow->SetNotifyWindow(m_hWnd); IFR(m_spIAniManager->SetManagerEventHandler(spIAniEventHandler)); IFR(m_spIAniManager->CreateAnimationVariable(1.0,&m_spIAniVarRed)); IFR(m_spIAniVarRed->SetLowerBound(0)); IFR(m_spIAniVarRed->SetUpperBound(1.0)); IFR(m_spIAniManager->CreateAnimationVariable(1.0,&m_spIAniVarGreen)); IFR(m_spIAniVarGreen->SetLowerBound(0)); IFR(m_spIAniVarGreen->SetUpperBound(1.0)); IFR(m_spIAniManager->CreateAnimationVariable(1.0,&m_spIAniVarBlue)); IFR(m_spIAniVarBlue->SetLowerBound(0)); IFR(m_spIAniVarBlue->SetUpperBound(1.0)); } void CreateDeviceResource() { //Direct2D CRect rc; GetClientRect(&rc); D2D1_SIZE_U size = SizeU(rc.Width(),rc.Height()); IFR(m_spD2dFactory->CreateHwndRenderTarget( RenderTargetProperties(), HwndRenderTargetProperties(m_hWnd,size), &m_spHwndRT)); D2D1_COLOR_F color = ColorF(ColorF::Red); IFR(m_spHwndRT->CreateSolidColorBrush(color,&m_spBkgndBrush)); CComPtr<ID2D1GradientStopCollection> spStopColl = NULL; D2D1_GRADIENT_STOP stops2[] = { {0.25f,ColorF(ColorF::Red)}, {0.5f,ColorF(ColorF::Yellow)}, {0.75f,ColorF(ColorF::Blue)} }; IFR(m_spHwndRT->CreateGradientStopCollection( stops2, ARRAYSIZE(stops2), &spStopColl)); IFR(m_spHwndRT->CreateLinearGradientBrush( LinearGradientBrushProperties(Point2F(0,0),Point2F(100,0)), spStopColl, &m_spTextBrush)); //DirectWrite IFR(m_spDWriteFactory->CreateTextFormat( _T("Courier New"), nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 48, _T("zh-Hans"), &m_spTextFormat)); m_spTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); m_spTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); } void DiscardDeviceResource() { ATLTRACE("DiscardDeviceResource\n"); m_spTextBrush = NULL; m_spBkgndBrush = NULL; m_spHwndRT = NULL; m_spTextFormat = NULL; } void Render() { if (!m_spHwndRT) CreateDeviceResource(); HRESULT hr = S_OK; m_spHwndRT->BeginDraw(); m_spHwndRT->SetTransform(Matrix3x2F::Identity()); //m_spHwndRT->Clear(ColorF(ColorF::White)); DOUBLE red=0, green=0, blue=0; m_spIAniVarRed->GetValue(&red); m_spIAniVarGreen->GetValue(&green); m_spIAniVarBlue->GetValue(&blue); m_spBkgndBrush->SetColor(ColorF(red,green,blue)); D2D1_SIZE_F size = m_spHwndRT->GetSize(); //Fill the background with randomly generated color D2D1_RECT_F rect = RectF(0,0,size.width,size.height); m_spHwndRT->FillRectangle(rect,m_spBkgndBrush); //Rotate the render target and draw text D2D1_POINT_2F center = Point2F(size.width/2,size.height/2); FLOAT degree = red*360.0f; m_spHwndRT->SetTransform(Matrix3x2F::Rotation(degree,center)); m_spTextBrush->SetEndPoint(Point2F(size.width,0)); CString text = _T("Direct2D&DirectWrite&Windows Animation"); m_spHwndRT->DrawText( text, text.GetLength(), m_spTextFormat, rect, m_spTextBrush); hr = m_spHwndRT->EndDraw(); if (hr == D2DERR_RECREATE_TARGET) DiscardDeviceResource(); } void ChangeColor() { DOUBLE red = ((DOUBLE)rand())/RAND_MAX; DOUBLE green = ((DOUBLE)rand())/RAND_MAX; DOUBLE blue = ((DOUBLE)rand())/RAND_MAX; const UI_ANIMATION_SECONDS DURATION = 0.5; const DOUBLE ACCEL_RATIO = 0.5; const DOUBLE DECEL_RATIO = 0.5; CComPtr<IUIAnimationStoryboard> spStoryBoard; IFR(m_spIAniManager->CreateStoryboard(&spStoryBoard)); CComPtr<IUIAnimationTransition> spITransRed; IFR(m_spIAniTransLib->CreateAccelerateDecelerateTransition( DURATION, red, ACCEL_RATIO, DECEL_RATIO, &spITransRed)); CComPtr<IUIAnimationTransition> spITransGreen; IFR(m_spIAniTransLib->CreateAccelerateDecelerateTransition( DURATION, green, ACCEL_RATIO, DECEL_RATIO, &spITransGreen)); CComPtr<IUIAnimationTransition> spITransBlue; IFR(m_spIAniTransLib->CreateAccelerateDecelerateTransition( DURATION, blue, ACCEL_RATIO, DECEL_RATIO, &spITransBlue)); IFR(spStoryBoard->AddTransition(m_spIAniVarRed,spITransRed)); IFR(spStoryBoard->AddTransition(m_spIAniVarGreen,spITransGreen)); IFR(spStoryBoard->AddTransition(m_spIAniVarBlue,spITransBlue)); UI_ANIMATION_SECONDS timeNow; IFR(m_spIAniTimer->GetTime(&timeNow)); spStoryBoard->Schedule(timeNow); } }; #pragma warning(pop)与SDK Sample不同的是对IUIAnimationManagerEventHandler接口的实现以及通知窗口的设置,感觉用ATL风格的实现更加优雅,代码也要简洁很多:
CComPtr<IUIAnimationManagerEventHandler> spIAniEventHandler; IFR(CAnimationEventHandler::CreateInstance(&spIAniEventHandler)); CComPtr<IAnimationNotifyWindow> spIAniNotifyWindow; IFR(spIAniEventHandler->QueryInterface(&spIAniNotifyWindow)); spIAniNotifyWindow->SetNotifyWindow(m_hWnd); IFR(m_spIAniManager->SetManagerEventHandler(spIAniEventHandler));实现效果:
当用鼠标点击窗口时,窗口会平滑的变化背景色,而窗口中的文字则会以“动画”的形式旋转。
相关文章推荐
- WTL-Direct2D,DirectWrite,Windows Animation
- Direct2D (39) : 使用 IDWriteTextLayout.Draw() 方法绘制文本
- Direct2D (34) : 开始学习 DirectWrite
- WP8 中 WIC, Direct2D, DirectWrite替代方案 (Direct3D 11 文字系统 Font Management)
- WTL-DWM,Direct2D
- Direct2D (41) : 文本命中测试 - IDWriteTextLayout.HitTestPoint()
- Direct2D DirectWrite绘制文字
- Direct2D (42) : 在文本布局中嵌入图片 IDWriteTextLayout.SetInlineObject()
- Direct2D DirectWrite绘制文字
- Direct2D中DirectWrite处理WM_SIZE消息
- Direct2D (43) : IDWriteGdiInterop 接口
- Direct2D (36) : RenderTarget.DrawText() 与 IDWriteTextFormat
- Direct2D (38) : RenderTarget.DrawTextLayout() 与 IDWriteTextLayout
- Direct2D中的DirectWrite
- 使用WIC将Direct2D绘制的图形保存为文件
- [Direct2D]DX11中的2D显示
- Direct2D编程入门
- SharpDX之Direct2D教程II——加载位图文件和保存位图文件
- [Direct2D1.1教程] Direct2D特效概览
- direct path read,direct path write