您的位置:首页 > 其它

Direct2D绘制的MFC控件

2013-06-07 16:52 483 查看

1.要点

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

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

[code]//D2dProgressBar.h
#pragma once

#include "afxwin.h"
#include <d2d1.h>
#include <d2d1helper.h>
#include <d2derr.h>
#pragma comment(lib, "d2d1.lib")

// 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);
};
// D2dProgressBar.cpp : implementation file
//

#include "stdafx.h"
#include "D2dProgressBar.h"
using namespace D2D1;

//
// 释放模板.
//
template<typename Type>
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;
	Invalidate(FALSE);		//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);
	Invalidate(FALSE);		//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();
	Invalidate(FALSE);		//Repaint
	
	CWnd::OnLButtonUp(nFlags, point);
}

3.测试所创建的控件

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: