`
java-mans
  • 浏览: 11819176 次
文章分类
社区版块
存档分类
最新评论

MFC(绘图与保存,孙鑫C++第十一讲笔记整理)

 
阅读更多

前面画图步骤直接上略了,因为跟第十讲的步骤是一样的,这里不再累赘

1.创建4个菜单,为其添加消息响应,用成员变量保存绘画类型。添加LButtonDownUp消息。

2.当窗口重绘时,如果想再显示原先画的数据,则需要保存数据。为此创建一个新类来记录绘画类型和两个点。

class CGraph

{

public:

CPoint m_ptOrigin;//起点

CPoint m_ptEnd;//终点

UINT m_nDrawType;//绘画类型

CGraph();

CGraph(UINT m_nDrawType,CPoint m_ptOrigin,CPoint m_ptEnd);//此为构造函数。

virtual ~CGraph();};

然后在void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)中加入如下代码

//CGraph graph(m_nDrawType,m_ptOrigin,point);//不能用局部变量

//m_ptrArray.Add(&graph);//加入这种指针数组中

/* OnPrepareDC(&dc);//这个函数中可以重新设置窗口原点,对于滚动条中,保存数据前要调用此函数

dc.DPtoLP(&m_ptOrigin);//将设备坐标转换为逻辑坐标

dc.DPtoLP(&point);//

CGraph *pGraph=new CGraph(m_nDrawType,m_ptOrigin,point);//在堆中创建新的对象

m_ptrArray.Add(pGraph);*///加入到指针数组中

GraphicView.h中有如下代码

CPtrArray m_ptrArray;

OnDraw中重画时调出数据

for(int i=0;i<m_ptrArray.GetSize();i++)

3.CView::OnPaint()调用了OnDraw(),但在void CGraphicView::OnPaint()MFCWizard没有调用OnDraw(),要注意这个区别。如果你此时想调用,必须手动添加代码。 OnDraw(&dc);

4.让窗口具有滚动条的功能。

1.CGraphicView的头文件中的CView全部替换成CSrollView

2.添加如下的代码

void CGraphicView::OnInitialUpdate()

{

CScrollView::OnInitialUpdate();

// TOD Add your specialized code here and/or call the base class

SetScrollSizes(MM_TEXT,CSize(800,600));//设置映射模式,设定窗口大小。OK

}

5.坐标系的转换,此处不再详细介绍,需要时请查阅相关资料。

6.解决重绘时线跑到上面的问题。为什么会错位?因为逻辑坐标和设备坐标没有对应起来。

解决方法:

OnLButtonDown画完图后,保存之前。调用

/* OnPrepareDC(&dc);//重新设置逻辑坐标的原点!!!

dc.DPtoLP(&m_ptOrigin);//设备坐标转化为逻辑坐标

dc.DPtoLP(&point);

CGraph *pGraph=new CGraph(m_nDrawType,m_ptOrigin,point);

m_ptrArray.Add(pGraph);*/

7.另外两种方法来保存数据。

一种是用CMetaFileDC

另一种是利用兼容DC,重绘时利用 pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatible,0,0,SRCCOPY);

void CHuiTuBaoView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	

	/*CClientDC ccdc(this);
	CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
	ccdc.SelectObject(cbrush);

	switch(m_leixing)
	{
	case 0:
		ccdc.SetPixel(point,RGB(0,0,0));
		break;

	case 1:
		ccdc.MoveTo(m_yuandian);
		ccdc.LineTo(point);
		break;

	case 2:
		ccdc.Rectangle(&CRect(m_yuandian,point));
		break;

	case 3:
		ccdc.Ellipse(&CRect(m_yuandian,point));
		break;
	default:
		break;
	}*/


	//CHUATU huatu(m_leixing,m_yuandian,point);//对象的声明周期在右大括号结束之后就销毁了,所以不可行
	//m_carray.Add(&huatu);

	CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);//使用指针,在堆栈分配了空间,与整个程序的声明周期一致,可行
	m_carray.Add(huatu);
	Invalidate();

	CView::OnLButtonUp(nFlags, point);
}


void CHuiTuBaoView::OnDraw(CDC* pDC)
{
	CHuiTuBaoDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here


	CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
	pDC->SelectObject(cbrush);

	for(int i=0;i<m_carray.GetSize();++i)
	{
		switch(((CHUATU*)m_carray.GetAt(i))->m_cleixing)
		{
		case 0:
			pDC->SetPixel(((CHUATU*)m_carray.GetAt(i))->m_czhondian,RGB(255,0,0));
			break;
		
		case 1:
			pDC->MoveTo(((CHUATU*)m_carray.GetAt(i))->m_cyuandian);
			pDC->LineTo(((CHUATU*)m_carray.GetAt(i))->m_czhondian);
			break;

		case 2:
			pDC->Rectangle(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian));
			
			break;

		case 3:
			pDC->Ellipse(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian));
			break;
		default:
			break;
		}
	}

}


上面使用CPtrArray来保存CHUATU的指针,那能不能使用我们熟悉的Vector动态数组来操作呢。试试便知

试验证明是可以的。

在CXXView头文件中写上

include<vector>

using namespace std;

然后定义成员变量

vector<CHUATU*>vv;

void CHuiTuBaoView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	

	/*CClientDC ccdc(this);
	CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
	ccdc.SelectObject(cbrush);

	switch(m_leixing)
	{
	case 0:
		ccdc.SetPixel(point,RGB(0,0,0));
		break;

	case 1:
		ccdc.MoveTo(m_yuandian);
		ccdc.LineTo(point);
		break;

	case 2:
		ccdc.Rectangle(&CRect(m_yuandian,point));
		break;

	case 3:
		ccdc.Ellipse(&CRect(m_yuandian,point));
		break;
	default:
		break;
	}*/


	//CHUATU huatu(m_leixing,m_yuandian,point);
	//m_carray.Add(&huatu);

	/*CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);
	m_carray.Add(huatu);
	Invalidate();*/

	CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);
	vv.push_back(huatu);
	Invalidate();

	CView::OnLButtonUp(nFlags, point);
}


void CHuiTuBaoView::OnDraw(CDC* pDC)
{
	CHuiTuBaoDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here


	CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
	pDC->SelectObject(cbrush);

	/*for(int i=0;i<m_carray.GetSize();++i)
	{
		switch(((CHUATU*)m_carray.GetAt(i))->m_cleixing)
		{
		case 0:
			pDC->SetPixel(((CHUATU*)m_carray.GetAt(i))->m_czhondian,RGB(255,0,0));
			break;
		
		case 1:
			pDC->MoveTo(((CHUATU*)m_carray.GetAt(i))->m_cyuandian);
			pDC->LineTo(((CHUATU*)m_carray.GetAt(i))->m_czhondian);
			break;

		case 2:
			pDC->Rectangle(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian));
			
			break;

		case 3:
			pDC->Ellipse(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian));
			break;
		default:
			break;
		}
	}*/

	for(vector<CHUATU*>::iterator itera=vv.begin();itera!=vv.end();++itera)
	{
		switch((*itera)->m_cleixing)
		{
		case 0:
			pDC->SetPixel((*itera)->m_czhondian,RGB(255,0,0));
			break;

		case 1:
			pDC->MoveTo((*itera)->m_cyuandian);
			pDC->LineTo((*itera)->m_czhondian);
			break;

		case 2:
			pDC->Rectangle(&CRect((*itera)->m_cyuandian,(*itera)->m_czhondian));
			break;

		case 3:
			pDC->Ellipse(&CRect((*itera)->m_cyuandian,(*itera)->m_czhondian));
			break;

		}
	}

}


可以使用很多方法解决,不要丢了我们前面学习的C++知识喔。

下面是有关GDI映射的问题,具体也可以看我的Windows32GDI映射的博客

OnPrepareDC会随时根据滚动窗口的位置来调整视口的原点

下面是一个关于设置坐标位置的例子。

手动设置滚动条

1class CXXView : public CView--->class CXXView : public CScrollView

2把cpp文件中的CView全部替换成CScrollView

3设置滚动条的属性

void SetScrollSizes( int nMapMode, SIZE sizeTotal, const SIZE& sizePage = sizeDefault, const SIZE& sizeLine = sizeDefault );

在CXXView中添加一个虚函数OnInitUpdate函数

4添加一条代码,这个函数是在调用OnDraw之前调用的

void CHuiTuBaoView::OnInitialUpdate() 
{
	CScrollView::OnInitialUpdate();
	
	// TODO: Add your specialized code here and/or call the base class

	SetScrollSizes(MM_TEXT,CSize(800,600));
	
}


然后就可以显示滚动条了:

然后用老师讲的方法,可以解决坐标映射问题,上面的PPT有讲问题的现象和解决方法

void CHuiTuBaoView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	

	/*CClientDC ccdc(this);
	CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
	ccdc.SelectObject(cbrush);

	switch(m_leixing)
	{
	case 0:
		ccdc.SetPixel(point,RGB(0,0,0));
		break;

	case 1:
		ccdc.MoveTo(m_yuandian);
		ccdc.LineTo(point);
		break;

	case 2:
		ccdc.Rectangle(&CRect(m_yuandian,point));
		break;

	case 3:
		ccdc.Ellipse(&CRect(m_yuandian,point));
		break;
	default:
		break;
	}*/


	//CHUATU huatu(m_leixing,m_yuandian,point);
	//m_carray.Add(&huatu);

	/*CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);
	m_carray.Add(huatu);
	Invalidate();*/
	
	CClientDC ccdc(this);


	OnPrepareDC(&ccdc);
	ccdc.DPtoLP(&m_yuandian);
	ccdc.DPtoLP(&point);
	CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);
	vv.push_back(huatu);
	Invalidate();

	CScrollView::OnLButtonUp(nFlags, point);
}


这样就完美解决了。

OnPaint中调用了OnprepareDC和OnDraw函数,OnprepareDC就是用来调整(设备环境)视口的

使用原文件上下文保存图像,CMetaFileDC

在OnLButtonUp中,CMetaFileDC yuanwenjian是成员变量,构造函数中Create

CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
	yuanwenjiandc.SelectObject(cbrush);

	switch(m_leixing)
	{
	case 0:
		yuanwenjiandc.SetPixel(point,RGB(0,0,0));
		break;

	case 1:
		yuanwenjiandc.MoveTo(m_yuandian);
		yuanwenjiandc.LineTo(point);
		break;

	case 2:
		yuanwenjiandc.Rectangle(&CRect(m_yuandian,point));
		break;

	case 3:
		yuanwenjiandc.Ellipse(&CRect(m_yuandian,point));
		break;
	default:
		break;
	}


在OnDraw中

void CHuiTuBaoView::OnDraw(CDC* pDC)
{
	CHuiTuBaoDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here


	CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
	pDC->SelectObject(cbrush);


	HMETAFILE hmetafile;
	hmetafile=yuanwenjiandc.Close();
	pDC->PlayMetaFile(hmetafile);
	yuanwenjiandc.Create();
	DeleteMetaFile(hmetafile);}//一定要关闭,否则出错


如果还想要保存原来的图画,这这样

void CHuiTuBaoView::OnDraw(CDC* pDC)
{
	CHuiTuBaoDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here


	CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
	pDC->SelectObject(cbrush);


	HMETAFILE hmetafile;
	hmetafile=yuanwenjiandc.Close();
	pDC->PlayMetaFile(hmetafile);
	yuanwenjiandc.Create();
	yuanwenjiandc.PlayMetaFile(hmetafile);//保存上一次绘画的图案
	DeleteMetaFile(hmetafile);
}


CMetaFile只是保存的是绘图的命令,而不是文件

下面给打开和保存添加事件

void CHuiTuBaoView::OnFileSave() 
{
// TODO: Add your command handler code here
HMETAFILE hmetafile;
hmetafile=yuanwenjiandc.Close();
CopyMetaFile(hmetafile,"meta.wmf");
yuanwenjiandc.Create();
DeleteMetaFile(hmetafile);
}

void CHuiTuBaoView::OnFileOpen() 
{
	// TODO: Add your command handler code here
	HMETAFILE hmetafile;
	hmetafile=GetMetaFile("meta.wmf");
	yuanwenjiandc.PlayMetaFile(hmetafile);
	DeleteMetaFile(hmetafile);
	Invalidate();

}


使用另外一种方法保存,兼容DC

在OnLButtonUp中

CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
	CClientDC ccdc(this);

	if(!compatibledc)
	{
		compatibledc.CreateCompatibleDC(&ccdc);
		CRect rect;
		GetClientRect(&rect);
		CBitmap bitmap;
		bitmap.CreateCompatibleBitmap(&ccdc,rect.Width(),rect.Height());
		compatibledc.SelectObject(&bitmap);
		compatibledc.SelectObject(cbrush);
		compatibledc.BitBlt(0,0,rect.Width(),rect.Height(),&ccdc,0,0,SRCCOPY);//兼容位图跟普通不一样
	}
	yuanwenjiandc.SelectObject(cbrush);
	
	switch(m_leixing)
	{
	case 0:
		compatibledc.SetPixel(point,RGB(0,0,0));
		break;
		
	case 1:
		compatibledc.MoveTo(m_yuandian);
		compatibledc.LineTo(point);
		break;
		
	case 2:
		compatibledc.Rectangle(&CRect(m_yuandian,point));
		break;
		
	case 3:
		compatibledc.Ellipse(&CRect(m_yuandian,point));
		break;
	default:
		break;
	}


OnDraw中

	CRect rect;
	GetClientRect(&rect);
	pDC->BitBlt(0,0,rect.Width(),rect.Height(),&compatibledc,0,0,SRCCOPY);


分享到:
评论

相关推荐

    孙鑫 VC++ 深入详解书中源码

    《孙鑫 VC++ 深入详解》是一本深受程序员喜爱的VC++技术书籍,作者孙鑫以其深入浅出的讲解方式,详细剖析了VC++的底层机制和高级特性。书中的源码是理解理论知识的关键实践部分,通过分析和运行这些代码,读者可以更...

    c++课程设计绘图

    在本项目中,"c++课程设计绘图"是一个基于C++编程语言的课程设计项目,主要使用MFC(Microsoft Foundation Classes)库进行图形用户界面(GUI)开发,实现了二维平面绘图的功能。MFC是微软提供的一套C++类库,它封装...

    C++深入详解自学笔记

    这份笔记由孙鑫编撰,通过一系列的视频教程整理而成,涵盖了从基础语法到高级特性的全方位讲解。 在第一课中,讲解了Windows程序运行原理和程序编写流程,这是理解和编写任何Windows应用程序的基础。了解操作系统...

    C++深入详解笔记

    根据给定的文件信息,我们可以总结出一系列关于C++及其在Windows编程环境下应用的重要知识点,尤其是围绕孙鑫视频VC++深入详解的学习笔记。下面将详细展开这些知识点。 ### C++深入详解笔记概述 #### Windows程序...

    MFC深入浅出

    9. **MFC扩展库**:微软还提供了一组扩展库,如ATL(Active Template Library)和WTL(Windows Template Library),它们可以与MFC一起使用,以增强性能或实现特定功能。这部分可能会讨论如何结合使用这些扩展库。 ...

    C++编程游戏MFC编程的内容

    C++编程游戏,特别是涉及到MFC(Microsoft Foundation Classes)的部分,是学习C++高级特性以及Windows应用程序开发的一个重要实践领域。MFC是一个由微软提供的类库,它封装了Windows API,使得开发者能够更加方便地...

    C++视频教程-VC深入详解自学笔记(完全免费

    《C++视频教程-VC深入详解自学笔记》是一份全面且免费的学习资源,旨在帮助初学者和有一定基础的开发者深入理解C++编程语言,特别是通过Visual C++ (VC++)这一开发环境进行实践。教程由孙鑫整理,涵盖了从基础到高级...

    MFC小游戏代码:借鉴

    在编程领域,MFC(Microsoft Foundation Classes)是微软提供的一种C++库,用于构建Windows应用程序。MFC以其强大的功能和丰富的类库,为开发者提供了便捷的Windows GUI编程工具。在这个主题下,我们探讨的是如何...

    基于mfc的图像显示源程序

    在本文中,我们将深入探讨如何使用Microsoft Foundation Class (MFC) 库来开发一个基于C++的图像显示程序,特别关注“基于MFC的图像显示源程序”这一主题。MFC 是微软为Windows应用程序开发提供的一个强大的框架,它...

    地图着色程序(MFC)

    孙鑫老师的MFC教程是一个很好的起点,他通常会从基本概念讲起,逐步引导学习者掌握MFC的使用方法。在掌握基础知识后,再来看这个地图着色程序,就能更好地理解其背后的逻辑和MFC的应用。 在文件列表中提到的“地图...

    简单VC绘图板

    《简单VC绘图板》是基于Visual C++(简称VC)开发的一款基础的绘图工具,主要用于初学者理解和实践图形用户界面(GUI)编程。这款应用虽然功能简单,但足以展示基本的绘图原理和事件处理机制,对于学习Windows编程和MFC...

    VC学习 WIN API学习全面

    在《VC++深入详解学习笔记孙鑫 C++视频教程》中,作者孙鑫首先介绍了Windows程序运行的基本原理和程序编写流程。这是理解后续内容的基础,包括程序如何加载、执行以及与系统进行通信。这一部分将帮助初学者建立起对...

    VC++深入详解.rar

    8. **异常处理**:MFC集成C++的异常处理机制,提供了CException类及一系列派生类,帮助捕获和处理运行时错误。 通过深入学习《VC++深入详解》中的内容,开发者能够更好地理解Windows程序的运行机制,掌握MFC框架的...

    VC++深入详解学习笔记

    - **MFC框架介绍**:MFC(Microsoft Foundation Classes)是微软提供的一个C++类库,旨在简化Windows程序的开发。它封装了Windows API,提供了一套面向对象的接口,使得开发者可以更加高效地开发复杂的GUI应用程序。...

    Windows窗口创建

    MFC是微软提供的一种C++类库,它封装了Windows API,使得编写Windows程序变得更加方便。 首先,我们要理解窗口创建的基本流程。在Windows编程中,创建窗口主要涉及到以下几个步骤: 1. **定义消息队列和窗口类**:...

    VC++深入详解code

    《VC++深入详解code》是孙鑫老师的一部经典之作,涵盖了MFC、Windows编程、GDI、多线程、同步以及Socket等多个关键领域。这些主题对于深入理解VC++编程至关重要,下面将逐一进行详细解释。 1. **MFC(Microsoft ...

    VC++绘图控件实例源代码下载

    摘要:VC/C++源码,图形处理,图形绘制 VC++绘图控件实例源代码下载,此源代码为孙鑫VC++深入详解一书的随书实例,主要向VC++初学者讲解进行各种几何图形绘制的方法,本例可绘制圆形、矩形、椭圆、直线、点等,并可...

    VC++深入详解PPT.rar

    本资源集合是孙鑫老师的VC++深入详解系列课程的PPT文档,旨在帮助学习者全面理解并掌握VC++编程技术。通过这些PPT,你可以系统地学习到VC++的核心概念、编程技巧以及高级特性。以下是对每个PPT文档所涵盖知识点的...

Global site tag (gtag.js) - Google Analytics