Direct2D绘制的MFC控件

1.要点

  1. MFC中已有的控件都是使用GDI/GDI+绘制自身,因此不适合直接从这些已有控件中继承,而应当CWnd中继承,将控件所有外观绘制的工作都交给Direct2D完成;
  2. 重写OnEraseBkgnd()函数,返回TRUE,已通知框架,控件背景色已由Direct2D负责绘制,框架不需要再绘制背景色;
  3. 客户端在使用此控件时,需要在窗口初始化时修改窗口的样式为WS_CLIPCHILDREN,以防止客户端干扰控件自身的绘制。
  4. 在控件内部添加私有的Direct2D绘图相关的接口变量,具体的绘制过程和在窗口中绘图类似。
  5. 当控件被Resize或客户端设置了控件属性,控件需要立即重绘时,调用Invalidate(FALSE)。

2.一个简单Direct2D控件的实现代码

[cpp]  view plain copy
  1. <pre name="code" class="cpp">//D2dProgressBar.h  
  2. #pragma once  
  3.   
  4. #include "afxwin.h"  
  5. #include <d2d1.h>  
  6. #include <d2d1helper.h>  
  7. #include <d2derr.h>  
  8. #pragma comment(lib, "d2d1.lib")  
  9.   
  10. // CD2dProgressBar  
    class CD2dProgressBar : public CWnd  
    {  
    public:  
    CD2dProgressBar(void);  
    ~CD2dProgressBar(void);  




    private:  
    ID2D1Factory* m_pD2d1Factory;  
    ID2D1HwndRenderTarget* m_pRenderTarget;  
    ID2D1SolidColorBrush* m_pSolidColorBrush;  
    ID2D1LinearGradientBrush* m_pLinearGradientBrush;  




    private:  
    BOOL CreateDeviceIndependentResource();  
    BOOL CreateDeviceDependentResource();  
    void DiscardDeviceDependentResource();  
    void DestoryResource();  




    void Render();  
    void ResizeRenderTarget(int width,int height);  




    public:  
    void SetValue(int progressValue);  
    int GetValue(void);  




    private:  
    int m_ProgressValue; 


    public:  
    DECLARE_MESSAGE_MAP()  
    afx_msg void OnPaint();  
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);  
    afx_msg void OnSize(UINT nType, int cx, int cy);  
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);  
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);  
    };  
[cpp]  view plain copy
  1. // D2dProgressBar.cpp : implementation file  
  2. //  
  3.   
  4.   
  5. #include "stdafx.h"  
  6. #include "D2dProgressBar.h"  
  7. using namespace D2D1;  
  8.   
  9.   
  10. //  
  11. // 释放模板.  
  12. //  
  13. void SafeRelease(Type& pObjToRelease)  
    {  
    if(pObjToRelease)  
    {  
    pObjToRelease->Release();  
    pObjToRelease = 0;  
    }  
    }  




    // CD2dProgressBar  
    //D2dProgressBar.cpp  
    CD2dProgressBar::CD2dProgressBar(void)  
    :m_ProgressValue(0)  
    ,m_pD2d1Factory(NULL)  
    ,m_pRenderTarget(NULL)  
    ,m_pSolidColorBrush(NULL)  
    ,m_pLinearGradientBrush(NULL)  
    {  
    }  




    CD2dProgressBar::~CD2dProgressBar(void)  
    {  
    DestoryResource();  
    }  




    void CD2dProgressBar::SetValue(int progressValue)  
    {  
    ASSERT((progressValue>=0) && (progressValue<=100));  
    m_ProgressValue = progressValue;  
    //Repaint  
    }  




    int CD2dProgressBar::GetValue(void)  
    {  
    return m_ProgressValue;  
    }  




    BEGIN_MESSAGE_MAP(CD2dProgressBar, CWnd)  
    ON_WM_PAINT()  
    ON_WM_ERASEBKGND()  
    ON_WM_SIZE()  
    ON_WM_LBUTTONUP()  
    END_MESSAGE_MAP()  




    void CD2dProgressBar::OnPaint()  
    {  
    CPaintDC dc(this); // device context for painting  
    // TODO: Add your message handler code here  
    // Do not call CWnd::OnPaint() for painting messages  
    Render();  
    }  




    BOOL CD2dProgressBar::OnEraseBkgnd(CDC* pDC)  
    {  
    // TODO: Add your message handler code here and/or call default  
    return TRUE;  




    //return CWnd::OnEraseBkgnd(pDC);  
    }  




    BOOL CD2dProgressBar::CreateDeviceIndependentResource()  
    {  
    HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,&m_pD2d1Factory);  
    ASSERT(!hr);  
    return SUCCEEDED(hr);  
    }  




    BOOL CD2dProgressBar::CreateDeviceDependentResource()  
    {  
    ASSERT(m_pD2d1Factory != NULL);  
    ASSERT(m_pRenderTarget == NULL);  




    CRect rc;  
    GetClientRect(&rc);  
    D2D1_RENDER_TARGET_PROPERTIES prop = RenderTargetProperties();  
    HRESULT hr = m_pD2d1Factory->CreateHwndRenderTarget(  
    prop,  
    HwndRenderTargetProperties(m_hWnd,SizeU(rc.Width(),rc.Height())),  
    &m_pRenderTarget);  
    ASSERT(!hr);  
    if (SUCCEEDED(hr))  
    {  
    hr = m_pRenderTarget->CreateSolidColorBrush(ColorF(ColorF::LightSeaGreen),&m_pSolidColorBrush);  
    ASSERT(!hr);  




    ID2D1GradientStopCollection* pGradientStops = NULL;  
    D2D1_GRADIENT_STOP stops[2];  
    stops[0].color = ColorF(ColorF::Yellow);  
    stops[0].position = 0.0f;  
    stops[1].color = ColorF(ColorF::Red);  
    stops[1].position = 1.0f;  
    HRESULT hr = m_pRenderTarget->CreateGradientStopCollection(  
    stops,  
    2,  
    D2D1_GAMMA_2_2,  
    D2D1_EXTEND_MODE_CLAMP,  
    &pGradientStops);  
    ASSERT(!hr);  




    //Create linear gradient brush  
    hr = m_pRenderTarget->CreateLinearGradientBrush(  
    LinearGradientBrushProperties(Point2F(0,0),Point2F(0,40)),  
    pGradientStops,  
    &m_pLinearGradientBrush);  
    ASSERT(!hr);  




    SafeRelease(pGradientStops);  
    }  
    return SUCCEEDED(hr);  
    }  




    void CD2dProgressBar::DiscardDeviceDependentResource()  
    {  
    SafeRelease(m_pLinearGradientBrush);  
    SafeRelease(m_pSolidColorBrush);  
    SafeRelease(m_pRenderTarget);  
    }  




    void CD2dProgressBar::DestoryResource()  
    {  
    DiscardDeviceDependentResource();  




    SafeRelease(m_pD2d1Factory);  
    }  




    void CD2dProgressBar::Render()  
    {  
    ASSERT(m_pD2d1Factory);  
    if (m_pRenderTarget == NULL)  
    {  
    BOOL succeeded = CreateDeviceDependentResource();  
    if (!succeeded)  
    return;  
    }  




    if (m_pRenderTarget->CheckWindowState()& D2D1_WINDOW_STATE_OCCLUDED)  
    return;  




    CRect rc;  
    GetClientRect(&rc);  
    //rc.DeflateRect(8,8);  




    m_pRenderTarget->BeginDraw();  
    m_pRenderTarget->Clear(ColorF(ColorF::LightGray));  
    m_pRenderTarget->SetTransform(Matrix3x2F::Identity());  
    D2D1_ROUNDED_RECT boundRect = D2D1::RoundedRect(RectF(rc.left,rc.top,rc.right,rc.bottom),5,5);  
    int width = (rc.right-rc.left)*m_ProgressValue/100;  
    D2D1_ROUNDED_RECT filledRect = D2D1::RoundedRect(RectF(rc.left,rc.top,rc.left+width,rc.bottom),5,5);  
    //Draw the outline  
    m_pRenderTarget->DrawRoundedRectangle(boundRect,m_pSolidColorBrush);  
    //Fill the outline  
    m_pRenderTarget->FillRoundedRectangle(filledRect,m_pLinearGradientBrush);  
    HRESULT hr = m_pRenderTarget->EndDraw();  
    if (hr == D2DERR_RECREATE_TARGET)  
    {  
    DiscardDeviceDependentResource();  
    }  
    }  


    void CD2dProgressBar::ResizeRenderTarget(int width,int height)  
    {  
    if (m_pRenderTarget)  
    {  
    m_pRenderTarget->Resize(SizeU(width,height));  
    }  
    }  


    BOOL CD2dProgressBar::PreCreateWindow(CREATESTRUCT& cs)  
    {  
    // TODO: Add your specialized code here and/or call the base class  
    BOOL succeeded = CreateDeviceIndependentResource();  
    ASSERT(succeeded);  




    return CWnd::PreCreateWindow(cs);  
    }  


    void CD2dProgressBar::OnSize(UINT nType, int cx, int cy)  
    {  
    CWnd::OnSize(nType, cx, cy);  




    // TODO: Add your message handler code here  
    ResizeRenderTarget(cx,cy);  
    //Repaint  
    }  




    void CD2dProgressBar::OnLButtonUp(UINT nFlags, CPoint point)  
    {  
    // TODO: Add your message handler code here and/or call default  
    CRect rc;  
    GetClientRect(&rc);  
    ASSERT(point.x >= rc.left && point.x <= rc.right  
    && point.y >= rc.top && point.y <= rc.bottom);  
     
    m_ProgressValue = 100*(point.x - rc.left)/rc.Width();  
    //Repaint  
     
    CWnd::OnLButtonUp(nFlags, point);  
    }  

3.测试所创建的控件

创建一个简单的MFC对话框,在OnInitDialog()函数中添加如下代码:

实际运行效果:

ScreenShot00073

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值