Direct2D绘制的MFC控件

1.要点

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

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

  1: //D2dProgressBar.h

  2: #pragma once

  3: 

  4: #include "afxwin.h"

  5: #include "D2dPrerequisite.h"

  6: 

  7: class CD2dProgressBar : public CWnd

  8: {

  9: public:

 10: 	CD2dProgressBar(void);

 11: 	~CD2dProgressBar(void);

 12: 

 13: private:

 14: 	ID2D1Factory* m_pD2d1Factory;

 15: 	ID2D1HwndRenderTarget* m_pRenderTarget;

 16: 	ID2D1SolidColorBrush* m_pSolidColorBrush;

 17: 	ID2D1LinearGradientBrush* m_pLinearGradientBrush;

 18: 

 19: private:

 20: 	BOOL CreateDeviceIndependentResource();

 21: 	BOOL CreateDeviceDependentResource();

 22: 	void DiscardDeviceDependentResource();

 23: 	void DestoryResource();

 24: 

 25: 	void Render();

 26: 	void ResizeRenderTarget(int width,int height);

 27: 

 28: public:

 29: 	void SetValue(int progressValue);

 30: 	int GetValue(void);

 31: 

 32: private:

 33: 	int m_ProgressValue;

 34: 

 35: public:

 36: 	DECLARE_MESSAGE_MAP()

 37: 	afx_msg void OnPaint();

 38: 	afx_msg BOOL OnEraseBkgnd(CDC* pDC);

 39: 	afx_msg void OnSize(UINT nType, int cx, int cy);

 40: 	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

 41: 	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

 42: };

  1: //D2dProgressBar.cpp

  2: #include "StdAfx.h"

  3: #include "D2dProgressBar.h"

  4: using namespace D2D1;

  5: 

  6: CD2dProgressBar::CD2dProgressBar(void)

  7: 	:m_ProgressValue(0)

  8: 	,m_pD2d1Factory(NULL)

  9: 	,m_pRenderTarget(NULL)

 10: 	,m_pSolidColorBrush(NULL)

 11: 	,m_pLinearGradientBrush(NULL)

 12: {

 13: }

 14: 

 15: CD2dProgressBar::~CD2dProgressBar(void)

 16: {

 17: 	DestoryResource();

 18: }

 19: 

 20: void CD2dProgressBar::SetValue(int progressValue)

 21: {

 22: 	ASSERT((progressValue>=0) && (progressValue<=100));

 23: 	m_ProgressValue = progressValue;

 24: 	Invalidate(FALSE);		//Repaint

 25: }

 26: 

 27: int CD2dProgressBar::GetValue(void)

 28: {

 29: 	return m_ProgressValue;

 30: }

 31: 

 32: BEGIN_MESSAGE_MAP(CD2dProgressBar, CWnd)

 33: 	ON_WM_PAINT()

 34: 	ON_WM_ERASEBKGND()

 35: 	ON_WM_SIZE()

 36: 	ON_WM_LBUTTONUP()

 37: END_MESSAGE_MAP()

 38: 

 39: void CD2dProgressBar::OnPaint()

 40: {

 41: 	CPaintDC dc(this); // device context for painting

 42: 	// TODO: Add your message handler code here

 43: 	// Do not call CWnd::OnPaint() for painting messages

 44: 	Render();

 45: }

 46: 

 47: BOOL CD2dProgressBar::OnEraseBkgnd(CDC* pDC)

 48: {

 49: 	// TODO: Add your message handler code here and/or call default

 50: 	return TRUE;

 51: 

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

 53: }

 54: 

 55: BOOL CD2dProgressBar::CreateDeviceIndependentResource()

 56: {

 57: 	HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,&m_pD2d1Factory);

 58: 	ASSERTHR(hr);

 59: 	return SUCCEEDED(hr);

 60: }

 61: 

 62: BOOL CD2dProgressBar::CreateDeviceDependentResource()

 63: {

 64: 	ASSERT(m_pD2d1Factory != NULL);

 65: 	ASSERT(m_pRenderTarget == NULL);

 66: 

 67: 	CRect rc;

 68: 	GetClientRect(&rc);

 69: 	D2D1_RENDER_TARGET_PROPERTIES prop = RenderTargetProperties();

 70: 	HRESULT hr = m_pD2d1Factory->CreateHwndRenderTarget(

 71: 		prop,

 72: 		HwndRenderTargetProperties(m_hWnd,SizeU(rc.Width(),rc.Height())),

 73: 		&m_pRenderTarget);

 74: 	ASSERTHR(hr);

 75: 	if (SUCCEEDED(hr))

 76: 	{

 77: 		hr = m_pRenderTarget->CreateSolidColorBrush(ColorF(ColorF::LightSeaGreen),&m_pSolidColorBrush);

 78: 		ASSERTHR(hr);

 79: 

 80: 		ID2D1GradientStopCollection* pGradientStops = NULL;

 81: 		D2D1_GRADIENT_STOP stops[2];

 82: 		stops[0].color = ColorF(ColorF::Yellow);

 83: 		stops[0].position = 0.0f;

 84: 		stops[1].color = ColorF(ColorF::Red);

 85: 		stops[1].position = 1.0f;

 86: 		HRESULT hr = m_pRenderTarget->CreateGradientStopCollection(

 87: 			stops,

 88: 			2,

 89: 			D2D1_GAMMA_2_2,

 90: 			D2D1_EXTEND_MODE_CLAMP,

 91: 			&pGradientStops);

 92: 		ASSERTHR(hr);

 93: 

 94: 		//Create linear gradient brush

 95: 		hr = m_pRenderTarget->CreateLinearGradientBrush(

 96: 			LinearGradientBrushProperties(Point2F(0,0),Point2F(0,40)),

 97: 			pGradientStops,

 98: 			&m_pLinearGradientBrush);

 99: 		ASSERTHR(hr);

100: 

101: 		SafeRelease(&pGradientStops);

102: 	}

103: 	return SUCCEEDED(hr);

104: }

105: 

106: void CD2dProgressBar::DiscardDeviceDependentResource()

107: {

108: 	SafeRelease(&m_pLinearGradientBrush);

109: 	SafeRelease(&m_pSolidColorBrush);

110: 	SafeRelease(&m_pRenderTarget);

111: }

112: 

113: void CD2dProgressBar::DestoryResource()

114: {

115: 	DiscardDeviceDependentResource();

116: 

117: 	SafeRelease(&m_pD2d1Factory);

118: }

119: 

120: void CD2dProgressBar::Render()

121: {

122: 	ASSERT(m_pD2d1Factory);

123: 	if (m_pRenderTarget == NULL)

124: 	{

125: 		BOOL succeeded = CreateDeviceDependentResource();

126: 		if (!succeeded)

127: 			return;

128: 	}

129: 

130: 	if (m_pRenderTarget->CheckWindowState()& D2D1_WINDOW_STATE_OCCLUDED)

131: 		return;

132: 

133: 	CRect rc;

134: 	GetClientRect(&rc);

135: 	//rc.DeflateRect(8,8);

136: 

137: 	m_pRenderTarget->BeginDraw();

138: 	m_pRenderTarget->Clear(ColorF(ColorF::LightGray));

139: 	m_pRenderTarget->SetTransform(Matrix3x2F::Identity());

140: 	D2D1_ROUNDED_RECT boundRect = D2D1::RoundedRect(RectF(rc.left,rc.top,rc.right,rc.bottom),5,5);

141: 	int width = (rc.right-rc.left)*m_ProgressValue/100;

142: 	D2D1_ROUNDED_RECT filledRect = D2D1::RoundedRect(RectF(rc.left,rc.top,rc.left+width,rc.bottom),5,5);

143: 	//Draw the outline

144: 	m_pRenderTarget->DrawRoundedRectangle(boundRect,m_pSolidColorBrush);

145: 	//Fill the outline

146: 	m_pRenderTarget->FillRoundedRectangle(filledRect,m_pLinearGradientBrush);

147: 	HRESULT hr = m_pRenderTarget->EndDraw();

148: 	if (hr == D2DERR_RECREATE_TARGET)

149: 	{

150: 		DiscardDeviceDependentResource();

151: 	}

152: }

153: 

154: void CD2dProgressBar::ResizeRenderTarget(int width,int height)

155: {

156: 	if (m_pRenderTarget)

157: 	{

158: 		m_pRenderTarget->Resize(SizeU(width,height));

159: 	}

160: }

161: 

162: BOOL CD2dProgressBar::PreCreateWindow(CREATESTRUCT& cs)

163: {

164: 	// TODO: Add your specialized code here and/or call the base class

165: 	BOOL succeeded = CreateDeviceIndependentResource();

166: 	ASSERT(succeeded);

167: 

168: 	return CWnd::PreCreateWindow(cs);

169: }

170: 

171: void CD2dProgressBar::OnSize(UINT nType, int cx, int cy)

172: {

173: 	CWnd::OnSize(nType, cx, cy);

174: 

175: 	// TODO: Add your message handler code here

176: 	ResizeRenderTarget(cx,cy);

177: 	Invalidate(FALSE);		//Repaint

178: }

179: 

180: void CD2dProgressBar::OnLButtonUp(UINT nFlags, CPoint point)

181: {

182: 	// TODO: Add your message handler code here and/or call default

183: 	CRect rc;

184: 	GetClientRect(&rc);

185: 	ASSERT(point.x >= rc.left && point.x <= rc.right

186: 		&& point.y >= rc.top && point.y <= rc.bottom);

187: 	

188: 	m_ProgressValue = 100*(point.x - rc.left)/rc.Width();

189: 	Invalidate(FALSE);		//Repaint

190: 	

191: 	CWnd::OnLButtonUp(nFlags, point);

192: }

3.测试所创建的控件

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

  1: // TODO: Add extra initialization here

  2: this->ModifyStyle(0,WS_CLIPCHILDREN);  //Modify the window style of the parent window

  3: 

  4: //Create our Direct2D control and set it's properties

  5: m_ProgressBar.Create(NULL,_T(""),WS_CHILD|WS_VISIBLE,CRect(50,50,150,100),this,1234);

  6: m_ProgressBar.SetValue(40);

实际运行效果:

ScreenShot00073

你可能感兴趣的:(mfc)