vs2019 MFC实现office界面的画图小项目(超超级详细)

举报
悲恋花丶无心之人 发表于 2021/02/05 00:23:04 2021/02/05
4.6k+ 0 1
【摘要】 这是针对于博客vs2019安装和使用教程(详细)的MFC实现office界面的画图小项目的新建示例 目录 一、创建项目 二、进入多个文档的控件界面 三、编写画图小程序(先从画矩形开始) 四、我们还可以再多画一些,例如箭头、直线和三角 五、图形的轮廓填充和内部填充(为了方便,都是统一更改颜色,一个一个改代码很麻烦) 六、序列化保存和读取文件 七、自己写一个导出...

这是针对于博客vs2019安装和使用教程(详细)的MFC实现office界面的画图小项目的新建示例


目录

一、创建项目

二、进入多个文档的控件界面

三、编写画图小程序(先从画矩形开始)

四、我们还可以再多画一些,例如箭头、直线和三角

五、图形的轮廓填充和内部填充(为了方便,都是统一更改颜色,一个一个改代码很麻烦)

六、序列化保存和读取文件

七、自己写一个导出文件的按钮

八、总结


vs2019安装MFC看这里:vs2019 安装MFC


一、创建项目

1.点击文件-->新建-->项目,选择MFC应用,点击下一步

2.项目名称为Draw,点击创建

3.可以看到有很多内容

4.应用程序类型有:

  • 单个文档
  • 多个文档
  • 基于对话框
  • 多个顶层文档

5.项目样式有:

  • MFC standard
  • Windows Explorer
  • Visual Studio
  • Office

6.这里应用程序类型选择多个文档项目样式选择Office

视觉样式和颜色选择默认的Office 2007(Blue theme)即可。

值得注意的是:Office会比默认选择的项目样式多一个Ribbon框,后面会说到~

7.点击下一步,我们来到文档模板属性,可以看到主框架描述文档类型名称等内容,这里可以默认不用修改

8.下一步,来到用户界面功能,可以看到Command bar里有三个选项,这里我们选择默认的使用功能区(ribbon)

9.下一步,来到高级功能,可以直接默认跳过

10.点击下一步来到最后一步——生成的类,可以看到生成的类和类名,我们选择默认的App即可,这样我们的头文件.cpp文件就是以项目名称命名

11.点击完成,之后看到左侧的解决方案资源管理器,这里包含了5个内容:

  • 引用
  • 外部依赖项
  • 头文件
  • 源文件
  • 资源文件

其中,我们可以在头文件和源文件里看到生成的.h和.cpp文件


二、进入多个文档的控件界面

1.因为是基于多个文档,所以我们需要了解如何在对话框上如何添加控件。因此我们可以双击 项目名称.rc2,进入资源视图

                                                                           

当然,我们也可以直接点击系统默认打开的底下的资源视图选项(注意:不能resource.h文件同时打开!!!)

                                                                    在这里哟~

如果不小心关闭了,也可以在菜单栏里 视图->资源视图里重新打开该视图

2.这里比较重要的是Menu部分,因为有很多MFC已经内置好的功能,例如主框架IDR_MAINFRAME里就有文件下拉菜单等选项,我们想要添加一个新的下拉菜单,只需要在右边的“请在此键入”输入内容,并且编写对应的代码即可。但这里博主并不在这里添加画图的功能。

3.博主这里要在Ribbon里添加画图的功能

4.点击右边的工具箱(竖着的,治疗颈椎~)

                                                               

然后点击Ribbon编辑器,可以看到有很多种类的控件

                                                                  


三、编写画图小程序(先从画矩形开始)

1.我们点击面板,然后拖动到窗口面板的右边,可以看到多了一个面板1

2.我们点击这个面板,在属性窗口中的外观下面,修改Caption,把面板1改为图形,这就算给这个面板改了名字

                                                     

3.我们再选择Ribbon工具箱里的按钮,同样拖动,至图形面板,如下,名字为button1

                                                     

4.修改这个按钮的属性中杂项的ID,改为ID_RECTANGLE

这里指的注意的就是这个ID,这个在MFC编程中十分重要,因为我们往往需要获取控件的ID号来对该控件进行函数编写消息处理等操作!!!

                                                     

5.既然是按钮,那就得有触发这个按钮所要执行的操作,右键这个按钮,我们选择添加事件处理程序

                                                      

6.弹出以下框

                                            

7.类列表我们选择CDrawView,点击确定

                                            

8.我们可以看到在DrawView.cpp中生成的命令函数

                                   

我们也可以看到在前面的代码中多了一个ON_COMMAND函数,说明我们确实添加了这样的一个按钮命令(注意:ID_RECTANGLE这个ID号就是对应的按钮的编号,&CDrawView::OnRectangle表示这个ID的按钮实现的命令函数)

                                      

这里的红波浪线提示没有这个ID,其实我们是添加了这个按钮的,可以在Resource.h中看到(注意打开Resource.h再去看资源试图是打不开的会报错,因此需要先关掉Resource.h再去访问资源试图!!!!!)

#define ID_RECTANGLE 32771
 

                 

这个IDE编辑器的小问题,我们可以选择重启vs2019打开就不会显示未定义ID了,如下,没有红色波浪线了

                             

9.现在的问题就是如何画图的问题:画矩形,则定义一个矩形类,写方法,在消息函数里新建对象即可;但是我们如果不满足只画矩形呢?画箭头、三角可不可以?这个时候我们就应该想到继承,即建一个抽象类graph,然后派生几个子类去完成这个功能。因此我们应该先新建一个graph抽象类:

我们右键头文件,选择添加-->新建项,弹出如下界面;

选择头文件(.h),名称为graph.h,点击确定

10.如下

                             

11.添加如下代码:

graph.h


      class graph :
     	public CObject
      {
      protected:
     	//边框
      	DECLARE_SERIAL(graph)
     	int left, up, right, down;
     	//选中状态
     	unsigned int state;
     	int sx, sy;
     	int  f_width = 5;
     	int fcolor = 0xffffff, bcolor = 0;
      public:
      	graph() :graph(50, 50, 100, 100) {
      	}
      	graph(int l, int u, int r, int d);
     	void Offset(int cx, int cy);
     	void onPress(int x, int y);	// 鼠标按下
     	int onMove(int cx, int cy);	// 鼠标移动
     	void onRelease(int x, int y);	// 鼠标释放
     	virtual void onDraw(CDC* pDC);
     	virtual int getGraphID() { return 0; }
     	virtual void Serialize(CArchive& ar);
     	void SetFillColor(int color);
     	void SetBorderColor(int color);
      	~graph();
      };
  
 

结果报了一堆错误,事实是因为我们新建的graph并没有和MFC本身的类关联起来

                                          

我们可以这样做:打开framework.hvs2017里是stdafx.h),我们在这里include一下我们的graph抽象类

如下(注意自己写的头文件要使用引号“”

#include "graph.h"
 

                                         

我们再回过头看graph.h,发现已经没有错误了

                                   

12.写了头文件,还要写对应的源文件

我们右键头文件,选择添加-->新建项,弹出如下界面;

选择C++文件(.cpp),名称为graph.cpp,点击确定

13.如下

                                 

14.填写如下代码

graph.cpp


      #include "framework.h"
      IMPLEMENT_SERIAL(graph, CObject, 1)
      graph::graph(int l, int u, int r, int d)
      {
      	left = l;
      	up = u;
      	right = r;
      	down = d;
      	state = 0;
      	fcolor = 0xffffff;
      }
      void graph::Offset(int cx, int cy)
      {
      	left += cx;
      	right += cx;
      	up += cy;
      	down += cy;
      }
      void graph::onPress(int x, int y)
      {
      	sx = x; sy = y;
      	state = 0;
     	//选中图形
     	if (left < x && x < right &&
      		up < y && y < down) {
      		state = 1;
     		return;
      	}
     	if (left - f_width / 2 < x && x < left + f_width / 2)	state |= 2;	// 选中左边
     	if (up - f_width / 2 < y && y < up + f_width / 2)	state |= 4;//选中上边
     	if (right - f_width / 2 < x && x < right + f_width / 2)	state |= 8;//选中右边
     	if (down - f_width / 2 < y && y < down + f_width / 2)	state |= 16;	// 选中下边
      }
      void graph::onRelease(int x, int y)
      {
      	state = 0;
      }
      void graph::SetBorderColor(int color)
      {
      	fcolor = color;
      }
      void graph::SetFillColor(int color)
      {
      	bcolor = color;
      }
      int graph::onMove(int x, int y)
      {
     	int cx, cy;
      	cx = x - sx; cy = y - sy;
      	sx = x; sy = y;
     	if (state == 1) {
      		Offset(cx, cy);		// 位移量cx,cy
      	}
     	if (2 == (state & 2)) {
      		left = x;
      	}
     	if (4 == (state & 4)) {
      		up = y;
      	}
     	if (8 == (state & 8)) {
      		right = x;
      	}
     	if (16 == (state & 16)) {
      		down = y;
      	}
     	return state == 0 ? 0 : 1;
      }
      void graph::Serialize(CArchive & ar)
      {
      	CObject::Serialize(ar);
     	if (ar.IsLoading()) {
      		ar >> left >> right >> up >> down >> f_width >> fcolor >> bcolor;
      	}
     	else
      	{
      		ar << left << right << up << down << f_width << fcolor << bcolor;
      	}
      }
      graph::~graph()
      {
      }
      void graph::onDraw(CDC * pDC) {
     	CBrush b(fcolor);
      	pDC->SelectObject(&b);
     	CRect r(left, up, right, down);
      	pDC->FillRect(&r, &b);
     	CPen p(PS_SOLID, 1, bcolor);
      	pDC->SelectObject(&p);
      	pDC->Rectangle(left, up, right, down);
      	pDC->MoveTo(left, up);
      	pDC->DrawText(_T("空图形"), -1, new CRect(left, up, right, down), DT_CENTER | DT_VCENTER | DT_SINGLELINE);
      }
  
 

15.根据上面的步骤,同样地,我们再新建一个矩形Rectangle类。这里直接列出头文件源文件

rectangle.h


      #pragma once
      #include "graph.h"
      class rectangle :
     	public graph
      {
      public:
     	//DECLARE_SERIAL(graph)
     	//void Serialize(CArchive& ar);
      	rectangle() :graph(50, 50, 100, 100) {}
      	rectangle(int l, int u, int r, int d);
     	void onDraw(CDC* pDC);
     	int getGraphID() { return 2; }
      	~rectangle();
      };
  
 

rectangle.cpp


      #include "framework.h"
      rectangle::rectangle(int l, int u, int r, int d) :graph(l, u, r, d)
      {
      	state = 0;
      	fcolor = 0xffffff;
      }
      void rectangle::onDraw(CDC* pDC)
      {
     	CBrush b(fcolor);
      	pDC->SelectObject(&b);
     	CRect r(left, up, right, down);
      	pDC->FillRect(&r, &b);
     	CPen p(PS_SOLID, 1, bcolor);
      	pDC->SelectObject(&p);
      	pDC->Rectangle(left, up, right, down);
      	pDC->MoveTo(left, up);
      }
      rectangle::~rectangle()
      {
      }
  
 

注意framework.h不要忘了加上:

#include "rectangle.h"
 

                                                  

16.由于我们需要可以添加多个图形,因此一个以graph对象构成的list是必不可少的。我们在DrawDoc.h文档头文件添加这个list,可以添加//操作下面

17.如下,可以看到又报错了:

std::list<graph*> graphList;
 

                                          

还是一样的,把list的头文件加到framework.h

#include <list>
 

                                        

再回去看DrawDoc.h,发现没有错误

                                 

18.我们再回到DrawView.cpp,填写矩形Rectangle消息处理程序,如下。代码解释为每点击一次矩形按钮,添加一个矩形:


      void CDrawView::OnRectangle()
      {
     	// TODO: 在此添加命令处理程序代码
      	CDrawDoc* pDoc = GetDocument();
      	ASSERT_VALID(pDoc);
     	if (!pDoc)
     		return;
      	pDoc->graphList.push_front(new rectangle(50, 50, 100, 100));
      	Invalidate();
      }
  
 

                      

19.我们还需要修改DrawView.cpp里的绘图代码部分

                               

添加如下代码(CDC* 后面的pDC取消注释


      // CDrawView 绘图
      void CDrawView::OnDraw(CDC* pDC)
      {
      	CDrawDoc* pDoc = GetDocument();
      	ASSERT_VALID(pDoc);
     	if (!pDoc)
     		return;
     	// TODO: 在此处为本机数据添加绘制代码
     	std::list<graph*>::iterator v;
     	for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) {
      		(*v)->onDraw(pDC);
      	}
      }
  
 

                    

20.运行程序,发现报错,这是预编译头的问题


      1>------ 已启动生成: 项目: Draw, 配置: Debug Win32 ------
      1>pch.cpp
      1>calendarbar.cpp
      1>ChildFrm.cpp
      1>Draw.cpp
      1>DrawDoc.cpp
      1>DrawView.cpp
      1>graph.cpp
      1>D:\vs2019_project\Draw\graph.cpp(110): fatal error C1010: 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "pch.h"?
      1>MainFrm.cpp
      1>rectangle.cpp
      1>D:\vs2019_project\Draw\rectangle.cpp(25): fatal error C1010: 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "pch.h"?
      1>正在生成代码...
      1>已完成生成项目“Draw.vcxproj”的操作 - 失败。
      ========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0==========
  
 

21.点击菜单栏的项目-->属性,选择C/C++-->预编译头,如下

改为不使用预编译头,点击确定

                             

22.我们再次运行代码,出现如下界面

23.我们点击图形面板矩形,可以看到窗口生成了一个矩形

24.然而,仅仅是生成一个矩形还是不够的;我们还需要添加鼠标的相关消息响应函数,例如鼠标移动鼠标按下鼠标抬起

右键源文件,点击类向导

                                            

25.如下

           

26.我们添加一个鼠标左键按下的消息响应:选择消息栏,选择WM_LBUTTONUP类名选择CDrawView,点击添加处理程序

如下

                  

                  

添加如下代码:


      void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
      {
     	// TODO: 在此添加消息处理程序代码和/或调用默认值
      	CDrawDoc* pDoc = GetDocument();
      	ASSERT_VALID(pDoc);
     	if (!pDoc)
     		return;
     	// TODO: 在此处为本机数据添加绘制代码
     	std::list<graph*>::iterator v;
     	for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) {
      		(*v)->onPress(point.x, point.y);
      	}
      	Invalidate();
     	//CView::OnLButtonDown(nFlags, point);
      }
  
 

                 

27.同样地,我们再添加鼠标左键松开

填写代码:


      void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
      {
     	// TODO: 在此添加消息处理程序代码和/或调用默认值
      	CDrawDoc* pDoc = GetDocument();
      	ASSERT_VALID(pDoc);
     	if (!pDoc)
     		return;
     	// TODO: 在此处为本机数据添加绘制代码
     	std::list<graph*>::iterator v;
     	for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) {
      		(*v)->onRelease(point.x, point.y);
      	}
      	Invalidate();
     	//CView::OnLButtonUp(nFlags, point);
      }
  
 

                     

28.同样地,我们再添加鼠标移动

填写代码:


      void CDrawView::OnMouseMove(UINT nFlags, CPoint point)
      {
     	// TODO: 在此添加消息处理程序代码和/或调用默认值
      	CDrawDoc* pDoc = GetDocument();
      	ASSERT_VALID(pDoc);
     	if (!pDoc)
     		return;
     	// TODO: 在此处为本机数据添加绘制代码
     	std::list<graph*>::iterator v;
     	for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) {
      		(*v)->onMove(point.x, point.y);
      	}
      	Invalidate();
     	//CView::OnMouseMove(nFlags, point);
      }
  
 

                   

29.运行程序,我们点击矩形,可以拖动这个矩形了!!

30.博主这里还做了放大缩小:把鼠标移到矩形边缘点击边缘就可以放大缩小~

31.当然,我们还可以再添加好几个矩形,因为别忘了博主是用list存储每次生成的graph对象的~


四、我们还可以再多画一些,例如箭头直线三角

1.相信前面的步骤大家了解的话,我相信添加按钮是很容易的,这里就直接给出博主的按钮ID

三角形:ID_TRIANGLE

箭头:ID_ARROW

直线:ID_LINE

                                                 

                                                

                                                

2.添加的类和方法:

*framework.h


      #include <afxwin.h> // MFC 核心组件和标准组件
      #include <afxext.h> // MFC 扩展
      #include "graph.h"
      #include "rectangle.h"
      #include "triangle.h"
      #include "arrow.h"
      #include "line.h"
      #include <list>
  
 

                                      

(1)三角形

triangle.h


      #pragma once
      #include "graph.h"
      class triangle :
     	public graph
      {
      protected:
      public:
      	triangle(int l, int u, int r, int d);
     	int getGraphID() { return 3; }
     	void onDraw(CDC* pDC);
      	~triangle();
      };
  
 

triangle.cpp


      #include "framework.h"
      triangle::triangle(int l, int u, int r, int d) :graph(l, u, r, d)
      {
      	state = 0;
      	fcolor = 0xffffff;
      }
      void triangle::onDraw(CDC* pDC)
      {
      	CPoint pts[3];
      	pts[0].x = (left + right) / 2;
      	pts[0].y = up;
      	pts[1].x = left;
      	pts[1].y = down;
      	pts[2].x = right;
      	pts[2].y = down;
     	CBrush b(fcolor);
      	pDC->SelectObject(&b);
     	CPen p(PS_SOLID, 1, bcolor);
      	pDC->SelectObject(&p);
      	pDC->Polygon(pts, 3);
      }
      triangle::~triangle()
      {
      }
  
 

(2)箭头:

arrow.h


      #pragma once
      #include "graph.h"
      class arrow :
     	public graph
      {
      public:
      	arrow(int l, int u, int r, int d);
     	void onDraw(CDC* pDC);
     	int getGraphID() { return 4; }
      	~arrow();
      };
  
 

arrow.cpp


      #include "framework.h"
      arrow::arrow(int l, int u, int r, int d) :graph(l, u, r, d)
      {
      }
      void arrow::onDraw(CDC* pDC)
      {
      	CPoint pts[2], pt[3];
      	pts[0].x = left;
      	pts[0].y = (up + down) / 2;
      	pts[1].x = (left + right) / 2;
      	pts[1].y = (up + down) / 2;
      	pt[0].x = (left + right) / 2;
      	pt[0].y = up;
      	pt[1].x = (left + right) / 2;
      	pt[1].y = down;
      	pt[2].x = right;
      	pt[2].y = (up + down) / 2;
     	CBrush b(fcolor);
      	pDC->SelectObject(&b);
     	CPen p(PS_SOLID, 1, bcolor);
      	pDC->SelectObject(&p);
      	pDC->Polygon(pts, 2);
      	pDC->Polygon(pt, 3);
      }
      arrow::~arrow()
      {
      }
  
 

(3)直线:

line.h


      #pragma once
      #include "graph.h"
      class line :
     	public graph
      {
      public:
      	line() :line(50, 50, 100, 100) {}
      	line(int l, int u, int r, int d);
     	void onDraw(CDC* pDC);
     	int getGraphID() { return 1; }
      	~line();
      };
  
 

line.cpp


      #include "framework.h"
      line::line(int l, int u, int r, int d) :graph(l, u, r, d)
      {
      	state = 0;
      	fcolor = 0xffffff;
      }
      void line::onDraw(CDC* pDC)
      {
      	CPoint pts[2];
      	pts[0].x = left;
      	pts[0].y = (up + down) / 2;
      	pts[1].x = right;
      	pts[1].y = (up + down) / 2;
     	CBrush b(fcolor);
      	pDC->SelectObject(&b);
     	CPen p(PS_SOLID, 1, bcolor);
      	pDC->SelectObject(&p);
      	pDC->Polygon(pts, 2);
      }
      line::~line()
      {
      }
  
 

3.添加的事件处理程序:

(1)三角形


      void CDrawView::OnTriangle()
      {
     	// TODO: 在此添加命令处理程序代码
      	CDrawDoc* pDoc = GetDocument();
      	ASSERT_VALID(pDoc);
     	if (!pDoc)
     		return;
      	pDoc->graphList.push_front(new triangle(50, 50, 100, 100));
      	Invalidate();
      }
  
 

(2)箭头


      void CDrawView::OnArrow()
      {
     	// TODO: 在此添加命令处理程序代码
      	CDrawDoc* pDoc = GetDocument();
      	ASSERT_VALID(pDoc);
     	if (!pDoc)
     		return;
      	pDoc->graphList.push_front(new arrow(50, 50, 100, 100));
      	Invalidate();
      }
  
 

(3)直线


      void CDrawView::OnLine()
      {
     	// TODO: 在此添加命令处理程序代码
      	CDrawDoc* pDoc = GetDocument();
      	ASSERT_VALID(pDoc);
     	if (!pDoc)
     		return;
      	pDoc->graphList.push_front(new line(50, 50, 100, 100));
      	Invalidate();
      }
  
 

4.运行程序,现在可以添加各种图形并且可以改变大小啦


五、图形的轮廓填充和内部填充(为了方便,都是统一更改颜色,一个一个改代码很麻烦)

1.添加一个面板,再添加两个按钮。按钮的选择是颜色按钮

                                                                              

2.如下

轮廓:ID_FILLCOLOR_LINE

内部:ID_FILLCOLOR_IN

                                                          

                                                            

3.添加的事件处理程序:

(1)需要在DrawView.cpp中添加MainFrm.h头文件

#include "MainFrm.h"
 

                                 

2)还需要在MainFrm.h中将m_wndRibbonBarprotected变为public,这样才能访问到这个变量,否则报错


      protected:  // 控件条嵌入成员
     	//CMFCRibbonBar m_wndRibbonBar;
      	CMFCRibbonApplicationButton m_MainButton;
      	CMFCToolBarImages m_PanelImages;
      	CMFCRibbonStatusBar  m_wndStatusBar;
      	COutlookBar m_wndNavigationBar;
      	CMFCShellTreeCtrl m_wndTree;
      	CCalendarBar m_wndCalendar;
      	CMFCCaptionBar m_wndCaptionBar;
      public:
      	CMFCRibbonBar m_wndRibbonBar;
  
 

                                  

  • 轮廓

      void CDrawView::OnFillcolorLine()
      {
     	// TODO: 在此添加命令处理程序代码
      	CDrawDoc* pDoc = GetDocument();
      	ASSERT_VALID(pDoc);
     	if (!pDoc)
     		return;
      	CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
      	CMFCRibbonColorButton* a = (CMFCRibbonColorButton*)((pFrame->m_wndRibbonBar).FindByID(ID_FILLCOLOR_LINE));
      	COLORREF c = a->GetColor();
     	std::list<graph*>::iterator v;
     	for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) {
      		(*v)->SetFillColor(c);
      	}
      	Invalidate();
      }
  
 
  • 内部

      void CDrawView::OnFillcolorIn()
      {
     	// TODO: 在此添加命令处理程序代码
      	CDrawDoc* pDoc = GetDocument();
      	ASSERT_VALID(pDoc);
     	if (!pDoc)
     		return;
      	CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
      	CMFCRibbonColorButton* a = (CMFCRibbonColorButton*)((pFrame->m_wndRibbonBar).FindByID(ID_FILLCOLOR_IN));
      	COLORREF c = a->GetColor();
     	std::list<graph*>::iterator v;
     	for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) {
      		(*v)->SetBorderColor(c);
      	}
      	Invalidate();
      }
  
 

4.运行程序

(1)轮廓变红,选择红色

                

如下

                         

(2)内部填充为绿色,选择绿色

         

如下

          


六、序列化保存和读取文件

1.修改DrawDoc.cpp的序列化部分,这是用于菜单栏里的保存打开图片所使用的

                                                                                    

                                     

2.修改代码如下:


      // CDrawDoc 序列化
      void CDrawDoc::Serialize(CArchive& ar)
      {
     	if (ar.IsStoring())
      	{
     		// TODO: 在此添加存储代码
      		ar << graphList.size();
     		for (auto it = graphList.begin(); it != graphList.end(); it++) {
      			ar << (*it)->getGraphID();
      			(*it)->Serialize(ar);
      		}
      	}
     	else
      	{
     		// TODO: 在此添加加载代码
     		for (auto it = graphList.begin(); it != graphList.end(); it++) {
     			delete* it;
      		}
      		graphList.clear();
     		int i, gid;
      		ar >> i;
      		graph* g;
     		while (i--) {
      			ar >> gid;
     			switch (gid)
      			{
     			case 1:
       g = new line();
      break;
     			case 2:
       g = new rectangle();
      break;
     			case 3:
       g = new triangle(0, 0, 0, 0);
      break;
     			case 4:
       g = new arrow(0, 0, 0, 0);
      break;
     			default:
       g = new graph();
      break;
      			}
      			g->Serialize(ar);
      			graphList.push_back(g);
      		}
      	}
      }
  
 

                                             

3.运行程序:博主随便画一个图

            

选择保存,默认路径和名字

可以看到有一个Draw1的文件

我们关掉程序,再运行程序,打开这个文件

               

可以看到多一个窗口,说明我们序列化成功!! 


七、自己写一个导出文件的按钮

1.再新建一个面板,拖入一个按钮,名字到导出图片,ID为ID_SAVE

                                                   

2.添加的事件处理程序:


      void CDrawView::OnSave()
      {
     	// TODO: 在此添加命令处理程序代码
     	CClientDC dc(this);
      	CRect rect;
      	CString saveFilePath;
      	BOOL  showMsgTag;
      	BOOL saveTag = FALSE;
      	GetClientRect(&rect);
      	HBITMAP hbitmap = CreateCompatibleBitmap(dc, rect.right - rect.left, rect.bottom - rect.top);
      	HDC hdc = CreateCompatibleDC(dc);
      	HBITMAP hOldMap = (HBITMAP)SelectObject(hdc, hbitmap);
      	BitBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, dc, 0, 0, SRCCOPY);
      	CImage image;
      	image.Attach(hbitmap);
     	if (!saveTag)
      	{
      		saveTag = TRUE;
      		showMsgTag = TRUE;
      		CString  strFilter = _T("位图文件(*.bmp)|*.bmp|JPEG 图像文件|*.jpg| GIF图像文件 | *.gif | PNG图像文件 | *.png |其他格式(*.*) | *.* || ");
     		CFileDialog dlg(FALSE, _T("bmp"), _T("iPaint1.bmp"), NULL, strFilter);
     		if (dlg.DoModal() != IDOK) return;
      		CString strFileName;
      		CString strExtension;
      		strFileName = dlg.m_ofn.lpstrFile;
     		if (dlg.m_ofn.nFileExtension == 0)
      		{
     			switch (dlg.m_ofn.nFilterIndex)
      			{
     			case 1:
       strExtension = "bmp";
      break;
     			case 2:
       strExtension = "jpg";
      break;
     			case 3:
       strExtension = "gif";
      break;
     			case 4:
       strExtension = "png";
      break;
      			}
      			strFileName = strFileName + "." + strExtension;
      		}
      		saveFilePath = strFileName;
      	}
     	else
      	{
      		showMsgTag = FALSE;
      	}
      	HRESULT hResult = image.Save(saveFilePath);
     	if (FAILED(hResult)) {
      		MessageBox(_T("保存图像文件失败!"));
      	}
     	else
      	{
     		if (showMsgTag)
      			MessageBox(_T("文件保存成功!"));
      	}
      	image.Detach();
      	SelectObject(hdc, hOldMap);
      }
  
 

3.运行程序,导入Draw1

点击导出图片,选择路径和文件名称,确定

4.提示文件保存成功!

5.双击打开这个文件iPaint1.bmp

6.可以看到成功打开(注意:这个文件不能用刚才自己写的MFC程序自带的打开来打开这个文件,因为打开的文件不是被序列化过的,因此打开会失败!

因此不能用这里的打开按钮


八、总结

1.MFC的按钮消息需要熟练掌握

2.鼠标消息的使用也很重要

3.序列化保存和普通的导出图片不是一码事

4.对于抽象类的使用,尤其是画各种图是很重要的

5.MFC内置的库函数需要熟练掌握(画笔、刷子等等)


后记:这篇博客废了博主老大的工夫,大家可以试试加个画圆啥的哈哈哈~


返回至原博客:

vs2019安装和使用教程(详细)

文章来源: nickhuang1996.blog.csdn.net,作者:悲恋花丶无心之人,版权归原作者所有,如需转载,请联系作者。

原文链接:nickhuang1996.blog.csdn.net/article/details/89946636

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。