首页 > 代码库 > C++MFC编程笔记day07 MFC单文档绘图保存、多文档绘图保存

C++MFC编程笔记day07 MFC单文档绘图保存、多文档绘图保存

 完善绘图例子(day06中的),加上保存功能
   1 设计和编写图形类 CShape
     1.1 成员变量
         CPoint m_ptBegin;
         CPoint m_ptEnd;
         UINT m_nType;
     1.2 支持序列化
         1.2.1 继承自CObject
         1.2.2 添加序列化的声明宏和实现宏
         1.2.3 重写虚函数Serilize(),在函数中,完成成员变量的序列化
   2 由于保存多个图形,引入MFC的集合类CObArray,保存的是CObject
     对象的地址。
   3 图形数据需要保存到文档类中,在该类添加集合类的成员变量
     CObArray m_arrShape;//图形的集合


   4 绘图时,保存图形数据。在视图类的鼠标弹起的消息处理函数中,


CShape *pShape=new CShape;
pShape->m_ptBegin=m_ptBegin;
pShape->m_ptEnd=m_ptEnd;
pShape->m_nType=m_nType;


CDrawDoc *pDoc=(CDrawDoc *)GetDocument();
        pDoc->m_arrShape.Add(pShape);


   5 解决窗口大小改变时的重绘问题
     在视图类的OnDraw()函数中,使用文档中的数据重新绘制图形


   6 在文档类的Serialize序列化操作




   7 修改字符串表
   IDR_MAINFRAME--查看msdn,CDocTemplate::GetDocString


   8 解决双击打开文件


     在应用程序的InitInstance()函数中,注册文件类型


     EnableShellOpen();

     RegisterShellFileTypes();//注册自定义文件类型,双击可直接打开


示例:

新建单文档MFC程序;

添加菜单:

修改字符串表:


ctrl+w 添加消息映射:

在视图类中,加菜单按钮的COMMAND和UPDATE_COMMAND_UI事件,然后视图类添加 WM_LBUTTONDOWN、WM_LBUTTONUP 、M_MOUSEMOVE消息事件。

主要核心代码:

//view的头文件中添加 成员变量和函数声明
public:
	CMFCdraw2Doc* GetDocument();
	CPoint m_ptBegin;//起点坐标
	CPoint m_ptEnd;//终点坐标
	UINT m_nType;//类型:1-直线,2-距形,3-圆
	BOOL m_bFlag;//是否开始画线
	void DrawShape(CDC *pDC, CPoint p1, CPoint p2);



// CMFCdraw2View construction/destruction
CMFCdraw2View::CMFCdraw2View()
{
	// TODO: add construction code here
	m_nType=0;
	m_bFlag=FALSE;
	m_ptBegin=m_ptEnd=0;
}
// CMFCdraw2View drawing

void CMFCdraw2View::OnDraw(CDC* pDC)
{
	CMFCdraw2Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	CBrush *pOldBrush=(CBrush *)
		pDC->SelectStockObject(NULL_BRUSH);

	for(int i=0;i<pDoc->m_arrShapes.GetSize();i++)
	{
		CShape *pshape=(CShape*)pDoc->m_arrShapes[i];
		switch(pshape->m_nType)
		{
		case 1:
			pDC->MoveTo(pshape->m_ptBegin);
			pDC->LineTo(pshape->m_ptEnd);
			break;
		case 2:
			pDC->Rectangle(pshape->m_ptBegin.x,pshape->m_ptBegin.y,
				pshape->m_ptEnd.x,pshape->m_ptEnd.y);
			break;
		case 3:
			pDC->Ellipse(pshape->m_ptBegin.x,pshape->m_ptBegin.y,
				pshape->m_ptEnd.x,pshape->m_ptEnd.y);
			break;
		}
	}
	pDC->SelectObject(pOldBrush);


	// TODO: add draw code for native data here
}

void CMFCdraw2View::OnDrawElipse() 
{
	// TODO: Add your command handler code here
	m_nType=3;
}

void CMFCdraw2View::OnDrawLine() 
{
	// TODO: Add your command handler code here
	m_nType=1;
}

void CMFCdraw2View::OnDrawRect() 
{
	// TODO: Add your command handler code here
	m_nType=2;
}

void CMFCdraw2View::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	// TODO: Add your message handler code here and/or call default
	m_bFlag=TRUE;//开始绘图
    m_ptBegin=m_ptEnd=point; //确定起点位置 
	CView::OnLButtonDown(nFlags,point);
}


void CMFCdraw2View::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	m_bFlag=FALSE;//结束画线
	CShape * pshape=new CShape;
	pshape->m_ptBegin=m_ptBegin;
	pshape->m_ptEnd=m_ptEnd;
	pshape->m_nType=m_nType;
	CMFCdraw2Doc *pDoc=(CMFCdraw2Doc*)GetDocument();
	pDoc->m_arrShapes.Add(pshape);//保存到文档的图形集合中
	CView::OnLButtonUp(nFlags, point);
}

void CMFCdraw2View::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	CClientDC dc(this);
	if(m_bFlag)
	{
		//擦线
		DrawShape(&dc,m_ptBegin,m_ptEnd);
		//画线
		DrawShape(&dc,m_ptBegin,point);
		//保存终点位置,为擦线准备
		m_ptEnd=point;
    }
	CView::OnMouseMove(nFlags, point);
}
void CMFCdraw2View::DrawShape(CDC *pDC, CPoint p1, CPoint p2)
{
	//设置绘图模式,R2_NOT与当前画线处颜色相反
	pDC->SetROP2(R2_NOT);
	//设置画刷为透明画刷
	CBrush *pOldBrush=
		(CBrush*)pDC->SelectStockObject(NULL_BRUSH);
	switch (m_nType)
	{
	case 1://直线
		pDC->MoveTo(p1);
		pDC->LineTo(p2);
		break;
	case 2://矩形
		pDC->Rectangle(p1.x,p1.y,p2.x,p2.y);
		break;
	case 3://椭圆
		pDC->Ellipse(p1.x,p1.y,p2.x,p2.y);
		break;
	}
	//恢复默认画刷
	pDC->SelectObject(pOldBrush);
	
}

void CMFCdraw2View::OnUpdateDrawElipse(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetRadio(m_nType==3);//更改选中的状态
}

void CMFCdraw2View::OnUpdateDrawLine(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetRadio(m_nType==1);
}

void CMFCdraw2View::OnUpdateDrawRect(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetRadio(m_nType==2);
}



//doc头文件添加成员变量和函数声明
public:
	CObArray m_arrShapes;
	UINT m_nShapeCount;//图形数量
	void releaseShapes();

//Doc类cpp中
CMFCdraw2Doc::CMFCdraw2Doc()
{
	// TODO: add one-time construction code here
	releaseShapes();
}

CMFCdraw2Doc::~CMFCdraw2Doc()
{
	releaseShapes();
}

BOOL CMFCdraw2Doc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;
	releaseShapes();
	// TODO: add reinitialization code here
	// (SDI documents will reuse this document)

	return TRUE;
}



/////////////////////////////////////////////////////////////////////////////
// CMFCdraw2Doc serialization

void CMFCdraw2Doc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		//存储图形数据前,先存储图形数量
		ar<<m_arrShapes.GetSize();
		for (int i=0;i<m_arrShapes.GetSize();i++)
		{
			CShape *pShape=(CShape *)m_arrShapes[i];
			ar<<pShape;
		}
		
	}
	else
	{
		//读取时,先要读取图形数量
		ar>>m_nShapeCount;
		for (int i=0;i<m_nShapeCount;i++)
		{
			CShape *pShape=NULL;
			ar>>pShape;
			m_arrShapes.Add(pShape);
			
		}
	}
}




/////////////////////////////////////////////////////////////////////////////
// CMFCdraw2Doc commands

void CMFCdraw2Doc::releaseShapes()
{
	for (int i=0;i<m_arrShapes.GetSize();i++)
	{
		delete m_arrShapes[i];
	}
    m_arrShapes.RemoveAll();
}


// Shape.h: interface for the CShape class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(CSHAPE_H)
#define CSHAPE_H

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//记录一个形状的类
class CShape : public CObject  
{
public:
	CShape();
	virtual ~CShape();
	virtual void Serialize( CArchive& ar );//序列化用的虚函数
public:
	CPoint m_ptBegin;//起点
	CPoint m_ptEnd;//终点
	UINT m_nType;//图形类型
	DECLARE_SERIAL(CShape)
};

#endif // !defined(CSHAPE_H)


//CShape.cpp
#include "stdafx.h"
#include "MFCdraw2.h"
#include "CShape.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_SERIAL(CShape,CObject,1)
CShape::CShape()
{
	m_ptBegin=m_ptEnd=0;
	m_nType=1;//直线
}

CShape::~CShape()
{
	
}
void CShape::Serialize( CArchive& ar )
{
	CObject::Serialize(ar);
	if (ar.IsStoring())
	{
		ar<<m_ptBegin<<m_ptEnd<<m_nType;
	}
	else
	{
		ar>>m_ptBegin>>m_ptEnd>>m_nType;
	}
}





MdiSquare例子的编写
   1 分析
     1.1 在视图类的OnDraw函数中,画网格


     1.2 添加颜色菜单
         1.2.1 实现菜单的单选功能
         1.2.2 实现菜单的设置当前颜色功能
     1.3 处理视图类的LBUTTONDOWN消息
         1.3.1 判断是否点击了某个单元格
               能够根据鼠标的当前位置得到点击的单元格的坐标
               设置该单元格对应的颜色值为当前颜色值
          1.3.2 在视图类的OnDraw函数中,填充单元格的颜色
                注意,先填充,后画网格
     1.4 文档类的数据
         1.4.1 定义一个二维的颜色数组,保存每一个网格的颜色值
         1.4.2 定义代表当前颜色值的变量
         1.4.3 在文档类的Serilize()函数中保存和加载数据


1 完成MdiSquares例子
  1.1 注意在向导的第4步,单击Advance按钮,打开对话框设置文件的扩展名。
      会在InitInstance函数中,自动添加以下代码,完成文件类型的注册
      EnableShellOpen();
      RegisterShellFileTypes(TRUE);
  1.2 设计菜单,并且添加菜单的消息处理函数
  1.3 在文档中添加单元格颜色的成员变量
      COLORREF m_clrGridColor;
      注意在构造函数中初始化
  1.4 在文档中添加了3个成员函数
      GetCurrentColor
      SetGridColor/GetGridColor
  1.5 实现Serilize()函数
  1.6 在视图类的OnDraw函数中画单元格,并使用文档中存储的网格颜色
      填充
  1.7 处理视图类的LBUTTONDOWN消息,在消息处理函数中,首先根据鼠标

      的单击位置,判断单元格,然后使用当前颜色填充该单元格




【示例稍后补充】