vs2019 MFC实现office界面的画图小项目

vs2019安装MFC

有许多新手不知道MFC在vs2019里的安装选项,其实它不会在勾选工作负载时自动默认勾选,而通常需要人为勾选,具体安装步骤如下:(安装时间不是很长,网速够快几分钟就下载完毕)

1.打开vs安装程序

2.选择Visual Studio扩展开发

3.选择C++ MFC 生成工具(x86 和 x64)进行安装

4.选择修改,等待安装

5.等待安装完成

6.安装完成,我们打开vs2019

7.我们创建新项目,可以看到已经有MFC应用这个选项

说明我们的MFC安装成功~

vs2019 MFC实现office界面的画图小项目

一、创建项目

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.h(vs2017里是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_wndRibbonBar从protected变为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 MFC实现office界面的画图小项目的文章就介绍到这了,更多相关vs2019 MFC 画图内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • VS2019安装配置MFC(安装vs2019时没有安装mfc)

    1.查看vs2019里面有没有配置MFC 新建项目,如果能在右边找到MFC应用则配置了,否则没有 2.*如果没有安装,将右边的的竖直移动条拉到底部,点击安装多个工具和供能* 3.选中在C++桌面开发==>在右侧选中相关功能==>点击修改 到此这篇关于VS2019安装配置MFC(安装vs2019时没有安装mfc)的文章就介绍到这了,更多相关VS2019安装配置MFC内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

  • VS2019以及MFC的安装详细教程

    本文为大家分享了VS2019以及MFC的安装详细教程,供大家参考,具体内容如下 一.安装过程: 1.搜索visual studio 进入官网. 2.选择community 2019下载. 3.现在完成后点击安装,等待安装完成 4.自动弹出一下界面,工作负载这里勾选使用C++的桌面开发和Visual Studio 扩展开发.另外,在使用C++的桌面开发选中后的右侧安装详细信息栏中勾选适用于最新的v142生成工具的C++MFC(x86和x64)这一项.选中后点击安装.(一共勾选3个地方,如下图) 5

  • VS2019创建MFC程序的实现方法

    前言:本博客只是因为我正在上计算机图形学这门课,为了方便复习所写,所以内容的正确性不敢保证,各位观看之前请三思(欢迎大佬提出建议) 为VS2019安装MFC开发环境 打开Visual Studio Installer(在电脑应用里找就行,安装vs2019肯定少不了它),得到如下界面,点击修改(如果提示你需要更新vs,你只能更新完vs才有修改选项) 找到使用使用C++的桌面开发选项,便能找到如图所示的MFC组件,安装它 安装完成.... 创建MFC应用 1.打开VS,点击创建新项目,得到下图,选择

  • vs2019 MFC实现office界面的画图小项目

    vs2019安装MFC 有许多新手不知道MFC在vs2019里的安装选项,其实它不会在勾选工作负载时自动默认勾选,而通常需要人为勾选,具体安装步骤如下:(安装时间不是很长,网速够快几分钟就下载完毕) 1.打开vs安装程序 2.选择Visual Studio扩展开发 3.选择C++ MFC 生成工具(x86 和 x64)进行安装 4.选择修改,等待安装 5.等待安装完成 6.安装完成,我们打开vs2019 7.我们创建新项目,可以看到已经有MFC应用这个选项 说明我们的MFC安装成功~ vs201

  • Python画图小案例之多啦A梦叮当猫超详细注释

    一步步教你怎么用Python画多啦A梦叮当猫,进一步熟悉Python的基础画图操作. 分析:叮当猫由头.脸.眼.眼珠.鼻子.嘴.胡子.项带.铃当.身子.围嘴.手臂.手.脚组成. 其中:头.脸.眼.眼珠.鼻子.嘴.胡子组成一个部件:其余元件组成一个部件.废话不多说,上代码. 希望您给个关注给个赞,也算对我们的支持了. import math import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWi

  • Python画图小案例之小雪人超详细源码注释

    一步步教你怎么用Python画雪人,进一步熟悉Python的基础画图操作,废话不多说,上代码. 希望您给个关注给个赞,也算对我们的支持了. class Shape: # 基类(雪人各部件(形状)共有的属性) def __init__(self, cvns, points, fill): # 构造方法 画布 位置坐标 颜色 self.cvns = cvns # 画布 self.points = points # 坐标(x1, y1, x2, y2) self.fill = fill self.pi

  • 微信小程序实战之运维小项目

    前言 自从微信推出小程序以来,现在业界炒的非常的火,具说叫微信小程序是因为某公司不让叫应用号,我在朋友圈也看过pony的和张小龙朋友圈关于名字的讨论截图,不知道是真是假,反正名字是定了,叫啥无所谓,还是知道它是干啥的比较重要, 像网上说什么新风口了,原生APP以后没活路了等相关文章喜欢的可以多看看, 我们今天不会在产品层面上去介绍小程序,因为我们是搞运维的,所以我还是在运维层面怎么使用小程序. 今天我们用实际例子来讲解和普及小小程序如何使用,来实现类似IP138的功能,输入IP可以查看IP的详细

  • C语言学生信息管理系统小项目

    本文为大家分享了C语言学生信息管理系统小项目,供大家参考,具体内容如下 /* 运行环境:我是在linux里面用gcc编译的,在windows里应该也能运行,用的一些文件库函数都是c标准库,没有用linux的系统调用(纠正一下:system("clear")这个系统调用是linux的,windows里面用system("cls") ) (1)问题描述 学生信息包括:学号,姓名,年龄,性别,出生年月,地址,电话,E-mail等.试设计一学生信息管理系统,使之能提供以下功

  • Java练手小项目实现一个项目管理系统

    目录 前言: 一.项目需求 二.功能实现 三.具体模块的实现 四.总结 前言: 时隔多日,我们学习完java的面向对象阶段,毕竟需要付诸实践,这个小项目就 作为我们第一个java面向对象解决的项目,接下来就让我们一起进入项目的世界吧 一.项目需求 • 模拟实现一个基于文本界面的 < 项目开发团队分配管理软件 > • 熟悉 Java 面向对象的高级特性,进一步掌握编程技巧和调试技巧 •主要涉及以下知识点: Ø 类的继承性和多态性 Ø 对象的值传递.接口 Ø static 和 final 修饰符

  • Python PyQt5干货满满小项目轻松实现高效抠图去背景

    目录 简介 1.获取API 2.API使用方法 3.可视化桌面制作 4.逻辑实现 5.美化 6.信号与槽绑定 7.全部代码 8.界面展示 简介 结合学习的PyQt5,弄点小项目,做次记录. 此项目是使用了removebg的API,进行实现抠图功能,将人物的背景扣去.将次功能封装到桌面上. 1.获取API 先打开removebg的网站 点击上面的工具和API 再点击API Docs 最后点击Get API Key,当然要先登录 2.API使用方法 在API Docs 下面有使用方法 3.可视化桌面

  • C语言实现猜数字小项目

    学习完c语言循环.选择内容,我们对c语言有个初步的认识了,让我们来实现一个小项目吧!!! 1.猜数字小项目分析: 我们利用c语言制造出随机数来猜,在只知道范围的前提下我们无非有以下三种可能,猜大了.猜小了.猜对了.如果猜错了我们让玩家继续猜直到猜对为止,若猜对了给出选择是否继续玩哈!!! 2.项目实现 我们定义两个函数 菜单函数 void menu() {     printf("********************\n");     printf("***** 1.pl

  • 新手易懂的Java客户管理小项目

    目录 成果展示 功能一:添加客户 功能二:修改客户 功能三:客户删除 功能四:展示客户列表 思路分析 代码部分 1.数据存储部分: 2.函数功能部分: 3.可视化界面部分: 项目总结 每日一语:花开蝶自来!!! 前言:随着我把狂神的Java的基础篇看完,我觉得我应该是把Java的基础应该没什么问题了,所以我决定找一个小项目写写,所以我就看了尚硅谷的基础小项目,不看不知道,一看吓一跳,我发现我虽然看完了基础的部分,但是我自己用起来还是有很多不足的地方,好在我请教了一些大佬们帮我解决这些问题,在这里

  • Python实现敲击木鱼积累功德小项目

    前言:前几天上课闲着没事写了一个python敲击木鱼积累功德的小项目,当时纯粹就是写着玩,回顾一下鼠标事件的东西还记不记得,发现这个博客的点赞和收藏量还挺高的,我当时也没有把它当回事,后面也有很多人问怎么实现的,想让我再添加一些其他功能! 随着点赞量和关注量不断增高,我又重新看了一下博客,感觉过于简单了,实在不配当当时python热榜的第一,所以我又把代码给稍微大改了一下,在原来总体实现的基础上添加了如下功能! 我们先看原来的效果: 1:实现了点击鼠标会弹出切换功德+1的surface界面,鼠标

随机推荐