我的第一个MFC
我的第一个MFC是在图像软件设计课程中创建的,使用Visual Studio 2022软件,基于C++语言,依赖freeimage图像库,实现在窗口应用中对一幅图像进行各种处理功能(如中值滤波等)
一、“什么是MFC”
- 微软基础类库(Microsoft Foundation Classes,简称MFC)是微软公司提供的一个类库,以C++类的形式封装了Windows API
- MFC是一个框架,在Visual Studio里新建一个MFC的工程,开发环境会自动帮你生成许多文件
二、创建一个MFC
0.编译freeimage
下载freeimage,
解压压缩包,使用VS2022打开FreeImage.2017.sln,
选择debug、x64,菜单栏点击生成解决方案,等待完成后找到FreeImage和FreeImagePlus的h、lib、dll文件,
将这些文件拷贝到新建文件夹FreeImage_x64中的h、lib文件夹内,以h结尾的放到h文件夹,其余放到lib中。
一般将FreeImage_x64文件夹放到解决方案所在目录下,这样添加附加依赖项和附加库时,只需要填写相对路径即可。
1.在VS2022创建MFC
在VS2022启动页面选择创建新项目,然后进入新的页面选择”MFC应用“,然后设置项目名称及保存位置,最后对MFC的具体功能进行设置
2.编写代码前3步骤
- 设置启动项
因为1个解决方案可以包含多个项目,但启动项只能是1个,也就是只能对1个项目进行编译链接操作
- 修改属性——字符集、附加包含目录、附加库目录
在不同的配置(release、debug)和平台(x64、x86)下,属性是不同步的,我的MFC窗口是在debug、x86情况下编译和链接的,因此需要确保属性页面上方的配置和平台一致。
3.编辑代码
编辑pch.h
在pch.h将头文件包含进来
#include "scuimage.h"
编辑doc.h
在doc.h中Doc类的pulic下,创建一个变量
SCU::CImage* m_pImg;
编辑doc.cpp
在doc.cpp中定义析构函数和构造函数、MFC窗口初始化界面
- 析构函数
m_pImg = NULL;
- 析构函数
if (m_pImg != NULL)
delete m_pImg;
- 初始化界面
如果想让MFC一运行就显示一幅图,则可以在OnNewDocument()添加代码
BOOL CMyfreeImage1105Doc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: 在此添加重新初始化代码
// (SDI 文档将重用该文档)
m_pImg = new SCU::CImage;
m_pImg->Create(640, 480, 24);
return TRUE;
}
- 取消初始化
当然,可以在App(即解决方案名.cpp)程序中的InitInstance()函数定义内123行左右,添加如下代码,取消程序自动打开doc.cpp中OnNewDocument()函数创造的图。
// 分析标准 shell 命令、DDE、打开文件操作的命令行
CCommandLineInfo cmdInfo;
//ParseCommandLine(cmdInfo);
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;
编译链接
到了这一步已经可以编译链接了,点击三角按钮,弹出缺少FreeImagePlus.ll,我们将附加依赖库目录下的FreeImagePlus.ll、FreeImage.ll加入到解决方案所在目录下的Debug文件下即可,再次编译链接,得到如下结果图
增加绘图、滑动轴、打开、保存图片的功能
- 绘图、滑动轴
在view.cpp中定义MFC窗口绘图(OnDraw函数)、滑动轴(OnInitialUpdate)的功能。
OnDraw():
函数对应用程序窗口的客户区进行绘图。为了使该函数有效,先将参数入口中被屏蔽掉(注释掉)的pDC恢复出来;然后发现pDoc是一个Doc类实例的一个指针,因此通过该pDoc指针可以调用我们在Doc类中定义的成员变量m_pImg;又因为m_pImg是Cimage类实例的一个指针。
void CMyfreeImage1105View::OnDraw(CDC* pDC)
{
CMyfreeImage1105Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
pDoc->m_pImg->Draw(pDC, CPoint(0, 0));
}
OnInitialUpdate():
框架在第一次调用OnDraw前会调用OnInitialUpdate,因此OnInitialUpdate是设置滚动视图的逻辑尺寸和映射模式的最适合的地方。
void CMyfreeImage1105View::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CSize sizeTotal;
// TODO: 计算此视图的合计大小
//sizeTotal.cx = sizeTotal.cy = 100;
GetDocument()->m_pImg->GetRealizeSize(sizeTotal);
SetScrollSizes(MM_TEXT, sizeTotal);
}
- 打开、保存
在doc类试图下,选择重写,添加OnOpenDocument、OnSaveDocument函数到doc.cpp中,
重写OnOpenDocument()
BOOL CMyfreeImage1105Doc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
// TODO: 在此添加您专用的创建代码
m_pImg = new SCU::CImage;
m_pImg->Load(lpszPathName);
return TRUE;
}
重写OnSaveDocument()
BOOL CMyfreeImage1105Doc::OnSaveDocument(LPCTSTR lpszPathName)
{
// TODO: 在此添加专用代码和/或调用基类
//return CDocument::OnSaveDocument(lpszPathName);
m_pImg->Save(lpszPathName);
return CDocument::OnSaveDocument(lpszPathName);
}
增添菜单栏并为该栏赋予功能
- 添加菜单栏
在资源视图中,点击menu,鼠标双击“IDR_解决方案名TYPE”,在出现的窗口,“在此处键入”处输入菜单名字,然后在新跳出的具体功能栏输入新的具体功能名
- 为具体功能栏赋予功能
在view的类试图,找到事件,然后找到具体功能栏对应的标识符(本文为ID_green),点击添加代码,最后就会在view.cpp中创建该标识符对应的代码编辑区
然后,在该标识符所在代码区编写代码,实现具体功能。
比如,我想让图片变绿,代码例子如下:
void CMyFirstMFC1111View::Ongreen()
{
// TODO: 在此添加命令处理程序代码
GetDocument()->m_pImg->SetShowBank(SCU::CI_GREEN);
Invalidate(FALSE);
}
最后进行编译链接,验证功能
当添加多个具体功能栏时,会出现不知道图片运行的是哪个功能栏,因此可以在栏中“打勾”的方式显示当前运行的功能栏。
为了实现“打勾”,要在view类视图事件,所有具体功能栏都添加onUpdatexxx()函数,然后再函数内添加代码,如下:
pCmdUI->SetCheck(GetDocument()->m_pImg->GetShowBank() == SCU::CI_GREEN);
//其中CI_GREEN为标识符,要修改成对应具体功能栏对应的标识符
最后验证打勾功能,如下: