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);

实际运行效果:

Direct2D绘制的MFC控件

相关文章:

  • 2021-11-01
  • 2021-06-14
  • 2021-11-11
  • 2021-06-15
  • 2021-10-02
  • 2021-08-10
  • 2022-12-23
猜你喜欢
  • 2021-06-07
  • 2022-12-23
  • 2022-12-23
  • 2021-11-04
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案