太原网站制作哪儿好薇,营销型网站结构,网站建设 实训意见和建议,过期域名查询网站MFC使用教程【对初学者保姆型友好#xff01;】 目录 前提条件
1#xff1a;创建MFC应用程序
2. 项目结构解读
引用
外部依赖项
头文件
源文件
资源文件
文件功能详解
项目的主要流程
步骤2#xff1a;配置OpenCV
安装OpenCV
包含目录与库文件
步骤3#xff1…MFC使用教程【对初学者保姆型友好】 目录 前提条件
1创建MFC应用程序
2. 项目结构解读
引用
外部依赖项
头文件
源文件
资源文件
文件功能详解
项目的主要流程
步骤2配置OpenCV
安装OpenCV
包含目录与库文件
步骤3添加UI控件
添加控件
1. 创建MFC对话框应用程序
2. 设计UI界面
解决方法
3. 实现控件处理逻辑 前提条件
1. 安装Visual Studio 2019并确保安装了MFC组件。
什么是MFC呢 MFCMicrosoft Foundation Classes是微软基础类库以C类的形式封装了Windows API并且包含一个应用程序框架以减少应用程序开发人员的工作量。它抽象了Windows API提供了一个基于C的面向对象的方式使得程序员可以更容易地开发出图形用户界面GUI应用程序。 2. 安装OpenCV库并配置Visual Studio以便在项目中使用OpenCV。
1创建MFC应用程序
1. 打开Visual Studio 2019创建一个新的项目。
2. 选择“MFC应用”并点击“下一步”。 可见MFC有三个选项MFC ActiveX控件、MFC应用程序、MFC DLL。
MFC ActiveX 控件用来生成MFCActiveX控件程序。 MFC ActiveX控件程序
是一种基于微软基金类库Microsoft Foundation Class Library简称MFC开发的ActiveX控件程序。
ActiveX控件是一种软件组件技术允许开发者创建可重用的对象。
这些对象可以嵌入到不同的应用程序中比如网页中的控件、桌面应用程序中的组件等。什么是MFC ActiveX控件程序
MFCMicrosoft Foundation Class Library是一组类库用于简化Windows应用程序的开发。
它封装了Windows API为开发者提供了一个面向对象的编程接口。
ActiveX控件是一种COM组件对象模型组件通常用于在不同行业应用中提供交互式功能。
ActiveX控件可以插入到网页、桌面应用程序或其他支持OLE对象链接与嵌入技术的环境中。什么时候需要用MFC ActiveX控件程序
需要跨平台组件如果你需要开发一个控件它可以在不同的容器如网页、桌面应用程序等中使用
那么ActiveX控件是一个合适的选择。通过使用MFC开发者可以更方便地创建和管理这些控件。
已有MFC基础如果你的团队已经熟悉MFC并且有很多现有的MFC代码库那么使用MFC来开发ActiveX控件可以节省时间和精力。
需要复杂的用户界面MFC提供了大量的GUI控件和图形处理功能这些功能可以用于创建复杂的、交互式的用户界面。
Windows平台开发ActiveX控件主要针对Windows平台如果你的应用程序或目标用户群体主要在Windows环境下使用MFC ActiveX控件会是一个合理的选择。使用MFC ActiveX控件的步骤
创建项目在Visual Studio中创建一个MFC ActiveX控件项目。这将为你提供一个基本的框架包含必要的文件和设置。
设计控件使用MFC类和资源编辑器来设计控件的外观和行为。你可以添加按钮、文本框、图像等元素并定义它们的交互逻辑。
实现功能编写控件的功能代码。你可以处理用户输入、与其他组件交互、进行数据处理等。
测试和调试在开发过程中不断测试和调试控件确保它在预期的环境中正常工作。
发布和部署完成开发后将ActiveX控件打包并发布给用户。用户可以通过注册控件使用regsvr32命令在他们的系统中使用它。总结
MFC ActiveX控件程序在需要可重用的、跨平台的交互组件时非常有用特别是在Windows环境下。
如果你熟悉MFC并且需要创建复杂的用户界面MFC ActiveX控件程序是一个强大的工具。
MFC 应用程序用来生成MFC应用程序。 MFC DLL用来生成MFC动态链接库程序。 具体如何选择请参见下下文
MFC有三个选项MFC ActiveX控件、MFC应用程序、MFC DLL如何选择https://zhuanlan.zhihu.com/p/804853133
3. 配置项目名称和位置然后点击“创建”。 4. 在MFC应用程序向导中选择“基于对话框的应用程序”。 应用程序类型有三个选项——单个文档、多个文档、基于对话框。
单个文档像Windows记事本、Windows画图、Windows写字板这样的程序一个程序只有一个文档处于编辑状态。
多个文档像WordExcel这样可以在一个MDI窗口里面同时处理多个文档的类型。
基于对话框像Windows扫雷、纸牌那样直接在对话框进行操作的程序。用不着文档。【因此我们常常选这个】 5. 点击“完成”以生成基本的MFC应用程序框架。 报错如下 解决方案如下 还有一个需要注意的地方就是mfc项目名字中不能带有特殊字符。比如下划线横线等。不然还是会报错具体原因有待考究。 成功后就会进入到如下界面 MFC应用程序项目结构。在Visual C中创建MFC应用程序时IDE会生成一个基本的项目结构其中包括一些头文件、源文件和资源文件。这些文件和目录有不同的功能和用途。
2. 项目结构解读 引用
为了更好的说明截图来举例 有同一个解决方案中有多个项目。一个项目【ConsoleApplication2.1】要使用另一项目【Dll1】
引用决定了项目的生成顺序。有三个用处
1. 决定生成整个解决方案的项目顺序如果不引用Dll1点击生成整个解决方案时项目 生成顺序会是ConsoleApplication2.1Dll1【按照顺序从上到下】。结果是报错。因为ConsoleApplication2.1使用了Dll1可Dll1还没有生成所以ConsoleApplication2.1找不到Dll1的lib或dll文件。像这种情况很多公司常见这时候往往会多生成几遍解决方案错误会逐渐减少直至最后成功生成所有项目。 2. 用于生成单个项目如果我清理了解决方案然后右键生成ConsoleApplication2.1会报错找不到Dll1。所以这时候应该在“引用”中添加Dll1。然后右键生成ConsoleApplication2.1这时会先生成Dll1再生成ConsoleApplication2.1。 3. 用于导出省略了__declspec(dllexport)。导出库中需要导出的所有前边可省略__declspec(dllexport)。 外部依赖项
所谓外部依赖项就是工程中显式包含的那些头文件本身所包含的头文件非自己定义主要包含一些外部库。
例如 虽然在main里包含了一个windows.h但是windows.h本身就包含相当多的头文件。而这些头文件又包含更多的头文件。于是你的外部依赖项就变得很庞大。若想减少外部依赖项那就尽量避免包含不必要的头文件。不过根据编译器的行为可能编译时应该会过滤掉那些虽然包含进来但完全没有用到的头文件可以不必理会外部依赖项。 头文件
framework.h定义了项目所使用的MFC应用程序框架相关的头文件。通常包括预编译头文件的引用。 MFCApplication1.h这是主应用程序类的头文件一般从CWinApp或其派生类继承。 MFCApplication1Dlg.h这是对话框类的头文件用于定义主对话框类及其成员函数和变量。对于以对话框为基础的应用程序这是主要的用户界面。pch.h预编译头文件用于提高编译速度。会包含项目中常用的头文件。PCH全称为Pre-compiled Header被预先编译过的头文件对于比较大型的工程往往编译时间会很久通过使用PCH把那些不经常发生改动的头文件都预先编译出来就可以大大节省实际使用时候的编译时间。实际应用中还经常把外部调用的API的头文件编译为PCH比如调用STL、调用Windows的APIwindows.h等等。 使用PCH的缺点会减弱文件间的关联性。举个例子原本我有一个cpp包含了#include windows.h然后我把这些自己不会改的api的头文件放到PCH里那么之后我再看这个代码我就不知道这个cpp具体包含了哪些头文件了我只知道它用到了PCH但是不能一眼就看出来它包含了头文件windows.h。 Resource.h定义了资源的ID如对话框、控件、菜单、字符串等资源的标识符。targetver.h定义了目标版本的Windows平台用于确保项目能正确地在指定的平台上进行编译。
源文件
MFCApplication1.cpp主应用程序文件包含CWinApp派生类的实现代码如应用程序初始化和退出例程。MFCApplication1Dlg.cpp对话框类的实现文件包含主要的用户界面逻辑和事件处理函数。pch.cpp用于生成预编译头文件的源文件。
资源文件
MFCApplication1.ico应用程序图标文件。MFCApplication1.rc资源脚本文件包含应用程序的资源定义如图标、对话框、菜单等。这些资源在编译时被编译进应用程序的可执行文件中。其他的资源文件如字符串表等这些文件也会包含在资源文件中有时会在目录中显示。
文件功能详解
头文件 (.h)用于声明类、函数、变量等代码元素并提供必要的信息给源文件 (.cpp)。 源文件 (.cpp)包含程序的主要逻辑和实现代码引用了头文件中声明的内容。 资源文件 (.rc, .ico)这些文件提供了可视化资源对话框、菜单、图标等的定义和实现通常使用资源编辑器进行管理。 项目的主要流程
框架初始化MFCApplication1.cpp中的CWinApp派生类负责初始化应用程序框架。用户界面MFCApplication1Dlg.h和MFCApplication1Dlg.cpp中的对话框类负责展示和处理用户交互。资源管理各资源文件如.rc文件和.h文件中的ID定义提供UI元素和其他资源的定义和引用。
这个项目结构是MFC应用程序的标准形式可以有效地组织和管理项目代码和资源使开发者可以专注于应用功能的实现。 步骤2配置OpenCV
安装OpenCV
Releases - OpenCVopencv.org/releases/ 2. 配置Visual Studio项目
右键点击项目选择“属性”。 在“VC目录”下添加OpenCV的 包含目录和 库目录。 包含目录
包含目录与库文件
说明.h头文件是 编译时必须的lib是 链接时需要的dll是 运行时需要的。 不管我们编写的代码有多么简单都必须经过【 编译 → 链接】 的过程才能生成可执行文件 编译就是将我们编写的源代码 “翻译” 成计算机可以识别的二进制格式它们以目标文件的形式存在 链接就是一个 “打包” 的过程它将所有的目标文件以及系统组件合成一个可执行文件。 include文件包含头文件.h 或.hpp这些文件定义了函数、类、宏和变量的接口。
lib文件包含库文件动态库.so 或静态库.a这些文件是经过编译和链接的二进制文件包含了实现代码。
DLL文件函数可执行代码。本质上来说dll和exe的区别不大都是可执行文件只是没有直接执行的入口要通过其他进程来调用而已。 包含目录C:\Users\15135\Downloads\opencv490\opencv\build\include 库目录C:\Users\15135\Downloads\opencv490\opencv\build\x64\vc16\lib 库目录
在“链接器”-“输入”下添加OpenCV的库文件如opencv_worldXXX.lib。 步骤3添加UI控件
1. 打开资源视图找到对话框资源通常是IDD_[项目名]_DIALOG。 添加控件
使用拖放工具添加按钮、标签、目录选择控件等类似于PyQt的界面。
1. 创建MFC对话框应用程序
在Visual Studio中创建一个新的MFC应用程序并选择“对话框”作为应用程序类型。
2. 设计UI界面
说明如果找不到ui界面这样操作
先点击rc文件 点击右侧的DIALOG就会看到左侧是界面【一定要注意不要随意更改ID后面的值很容易滑动一下就改了如果改了要立刻改回来】。 注意要对应【aboutbox就是这个关于说明】
用资源编辑器设计对话框界面【主界面】添加以下控件
在对话框上添加了以下控件 按钮 (Button) “选择图像所在文件夹”ID设为IDC_BUTTON_FOLDER“图像处理”ID设为IDC_BUTTON_PROCESS静态文本 (Static Text) “已选择的文件夹”ID设为IDC_STATIC_DIRECTORY日志显示ID设为IDC_STATIC_LOG编辑框 (Edit Control) 显示已选择的文件夹路径ID设为IDC_EDIT_DIRECTORY bug1 初学者写代码写着写着MFC右边工具箱不见了。 解决方法
判断工程的程序是否运行如果运行那就关闭如果没运行那就先运行再让他关闭F5调试ShiftF5关闭调试一般运行程序关闭工具箱自然浮现。或者多点几次界面上的按钮就有了。 3. 实现控件处理逻辑
要在MFC应用程序中实现控件处理逻辑需要在对话框类头文件MFCApplicationImageDealDlg.h中定义的类中添加控件变量和消息处理函数。
初始代码【项目创建一开始vs就帮我们创建了一些代码】如下
// MFCApplicationImageDealDlg.h: 头文件
//#pragma once// CMFCApplicationImageDealDlg 对话框
class CMFCApplicationImageDealDlg : public CDialogEx
{
// 构造
public:CMFCApplicationImageDealDlg(CWnd* pParent nullptr); // 标准构造函数// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD IDD_MFCAPPLICATIONIMAGEDEAL_DIALOG };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 实现
protected:HICON m_hIcon;// 生成的消息映射函数virtual BOOL OnInitDialog();afx_msg void OnSysCommand(UINT nID, LPARAM lParam);afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();DECLARE_MESSAGE_MAP()
};修改后的代码
// MFCApplicationImageDealDlg.h: 头文件
//#pragma once// CMFCApplicationImageDealDlg 对话框
class CMFCApplicationImageDealDlg : public CDialogEx
{// 构造
public:CMFCApplicationImageDealDlg(CWnd* pParent nullptr); // 标准构造函数// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD IDD_MFCAPPLICATIONIMAGEDEAL_DIALOG };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 实现
protected:HICON m_hIcon;// 生成的消息映射函数virtual BOOL OnInitDialog();afx_msg void OnSysCommand(UINT nID, LPARAM lParam);afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();DECLARE_MESSAGE_MAP()private:// 控件变量CButton m_btnSelectFolder;CButton m_btnProcess;CStatic m_staticDirectory;CEdit m_editDirectory;// 选定文件夹路径CString m_selectedFolderPath;void UpdateLog(const CString message);public:afx_msg void OnBnClickedButtonFolder();afx_msg void OnBnClickedButtonProcess();
};接下来需要在相应的实现文件MFCApplicationImageDealDlg.cpp中实现这些新增的函数和逻辑以及将相应的功能添加到对话框的事件处理函数中。
原始代码如下
// MFCApplicationImageDealDlg.cpp: 实现文件
//#include pch.h
#include framework.h
#include MFCApplicationImageDeal.h
#include MFCApplicationImageDealDlg.h
#include afxdialogex.h#ifdef _DEBUG
#define new DEBUG_NEW
#endif// 用于应用程序“关于”菜单项的 CAboutDlg 对话框class CAboutDlg : public CDialogEx
{
public:CAboutDlg();// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD IDD_ABOUTBOX };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 实现
protected:DECLARE_MESSAGE_MAP()
};CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);
}BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()// CMFCApplicationImageDealDlg 对话框CMFCApplicationImageDealDlg::CMFCApplicationImageDealDlg(CWnd* pParent /*nullptr*/): CDialogEx(IDD_MFCAPPLICATIONIMAGEDEAL_DIALOG, pParent)
{m_hIcon AfxGetApp()-LoadIcon(IDR_MAINFRAME);
}void CMFCApplicationImageDealDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);
}BEGIN_MESSAGE_MAP(CMFCApplicationImageDealDlg, CDialogEx)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()// CMFCApplicationImageDealDlg 消息处理程序BOOL CMFCApplicationImageDealDlg::OnInitDialog()
{CDialogEx::OnInitDialog();// 将“关于...”菜单项添加到系统菜单中。// IDM_ABOUTBOX 必须在系统命令范围内。ASSERT((IDM_ABOUTBOX 0xFFF0) IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX 0xF000);CMenu* pSysMenu GetSystemMenu(FALSE);if (pSysMenu ! nullptr){BOOL bNameValid;CString strAboutMenu;bNameValid strAboutMenu.LoadString(IDS_ABOUTBOX);ASSERT(bNameValid);if (!strAboutMenu.IsEmpty()){pSysMenu-AppendMenu(MF_SEPARATOR);pSysMenu-AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 设置此对话框的图标。 当应用程序主窗口不是对话框时框架将自动// 执行此操作SetIcon(m_hIcon, TRUE); // 设置大图标SetIcon(m_hIcon, FALSE); // 设置小图标// TODO: 在此添加额外的初始化代码return TRUE; // 除非将焦点设置到控件否则返回 TRUE
}void CMFCApplicationImageDealDlg::OnSysCommand(UINT nID, LPARAM lParam)
{if ((nID 0xFFF0) IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialogEx::OnSysCommand(nID, lParam);}
}// 如果向对话框添加最小化按钮则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序
// 这将由框架自动完成。void CMFCApplicationImageDealDlg::OnPaint()
{if (IsIconic()){CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_castWPARAM(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon GetSystemMetrics(SM_CXICON);int cyIcon GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(rect);int x (rect.Width() - cxIcon 1) / 2;int y (rect.Height() - cyIcon 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);}else{CDialogEx::OnPaint();}
}//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplicationImageDealDlg::OnQueryDragIcon()
{return static_castHCURSOR(m_hIcon);
}修改后的代码如下
// MFCApplicationImageDealDlg.cpp: 实现文件
//#include pch.h
#include framework.h
#include MFCApplicationImageDeal.h
#include MFCApplicationImageDealDlg.h
#include afxdialogex.h
#include atlimage.h // 用于处理图像
#include fstream#ifdef _DEBUG
#define new DEBUG_NEW
#endif// 用于应用程序“关于”菜单项的 CAboutDlg 对话框class CAboutDlg : public CDialogEx
{
public:CAboutDlg();// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD IDD_ABOUTBOX };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 实现
protected:DECLARE_MESSAGE_MAP()
};CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);
}BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()// CMFCApplicationImageDealDlg 对话框CMFCApplicationImageDealDlg::CMFCApplicationImageDealDlg(CWnd* pParent /*nullptr*/): CDialogEx(IDD_MFCAPPLICATIONIMAGEDEAL_DIALOG, pParent)
{m_hIcon AfxGetApp()-LoadIcon(IDR_MAINFRAME);
}void CMFCApplicationImageDealDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_BUTTON_FOLDER, m_btnSelectFolder);DDX_Control(pDX, IDC_BUTTON_PROCESS, m_btnProcess);DDX_Control(pDX, IDC_STATIC_DIRECTORY, m_staticDirectory);DDX_Control(pDX, IDC_EDIT_DIRECTORY, m_editDirectory);
}BEGIN_MESSAGE_MAP(CMFCApplicationImageDealDlg, CDialogEx)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON_FOLDER, CMFCApplicationImageDealDlg::OnBnClickedButtonFolder)ON_BN_CLICKED(IDC_BUTTON_PROCESS, CMFCApplicationImageDealDlg::OnBnClickedButtonProcess)
END_MESSAGE_MAP()// CMFCApplicationImageDealDlg 消息处理程序BOOL CMFCApplicationImageDealDlg::OnInitDialog()
{CDialogEx::OnInitDialog();// 将“关于...”菜单项添加到系统菜单中。// IDM_ABOUTBOX 必须在系统命令范围内。ASSERT((IDM_ABOUTBOX 0xFFF0) IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX 0xF000);CMenu* pSysMenu GetSystemMenu(FALSE);if (pSysMenu ! nullptr){BOOL bNameValid;CString strAboutMenu;bNameValid strAboutMenu.LoadString(IDS_ABOUTBOX);ASSERT(bNameValid);if (!strAboutMenu.IsEmpty()){pSysMenu-AppendMenu(MF_SEPARATOR);pSysMenu-AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 设置此对话框的图标。 当应用程序主窗口不是对话框时框架将自动// 执行此操作SetIcon(m_hIcon, TRUE); // 设置大图标SetIcon(m_hIcon, FALSE); // 设置小图标// TODO: 在此添加额外的初始化代码return TRUE; // 除非将焦点设置到控件否则返回 TRUE
}void CMFCApplicationImageDealDlg::OnSysCommand(UINT nID, LPARAM lParam)
{if ((nID 0xFFF0) IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialogEx::OnSysCommand(nID, lParam);}
}// 如果向对话框添加最小化按钮则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序
// 这将由框架自动完成。void CMFCApplicationImageDealDlg::OnPaint()
{if (IsIconic()){CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_castWPARAM(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon GetSystemMetrics(SM_CXICON);int cyIcon GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(rect);int x (rect.Width() - cxIcon 1) / 2;int y (rect.Height() - cyIcon 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);}else{CDialogEx::OnPaint();}
}//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplicationImageDealDlg::OnQueryDragIcon()
{return static_castHCURSOR(m_hIcon);
}void CMFCApplicationImageDealDlg::OnBnClickedButtonFolder()
{CFolderPickerDialog folderDlg;if (folderDlg.DoModal() IDOK){m_selectedFolderPath folderDlg.GetPathName();m_editDirectory.SetWindowText(m_selectedFolderPath);UpdateLog(_T(已选择的文件夹: ) m_selectedFolderPath);}
}void CMFCApplicationImageDealDlg::OnBnClickedButtonProcess()
{UpdateLog(_T(正在处理文件夹: ) m_selectedFolderPath);// 创建保存处理后图像的文件夹路径CString resultFolderPath m_selectedFolderPath _T(\\result);if (!CreateDirectory(resultFolderPath, NULL) GetLastError() ! ERROR_ALREADY_EXISTS)//如果文件夹创建成功或已存在【文件夹创建失败是因为已经存在】程序继续执行后续操作//否则【文件夹创建失败且不是因为已经存在的原因】程序会显示错误信息并停止处理。{AfxMessageBox(_T(无法创建处理后的图像文件夹), MB_OK | MB_ICONERROR);return;}// 图像处理逻辑CFileFind finder; // 创建一个 CFileFind 对象用于查找文件// CFileFind 是 MFC 提供的类用于在目录中查找文件。// 设置要查找的文件路径和模式CString strWildcard(m_selectedFolderPath); // 初始化查找路径为用户选择的文件夹路径strWildcard _T(\\*.jpg); // 在路径后面添加通配符 *.jpg 以查找所有 JPG 图像文件// 开始查找文件BOOL bWorking finder.FindFile(strWildcard); // 使用通配符查找文件返回查找的初始状态UpdateLog(_T(查找文件的初始状态: ) CString(bWorking ? _T(TRUE) : _T(FALSE))); // 记录初始查找状态while (bWorking){bWorking finder.FindNextFile(); //在调用 finder.FindFile 后finder.FindNextFile仍然遵循最初设定的查找模式//例如* .jpg并会继续查找该目录下的下一个符合模式的文件。UpdateLog(_T(bWorking 状态: ) CString(bWorking ? _T(TRUE) : _T(FALSE)));// 打印第一次调用 FindFile 找到的文件路径if (bWorking) {CString scenondFilePath finder.GetFilePath();UpdateLog(_T(第2次找到的文件路径: ) scenondFilePath);}if (finder.IsDots() || finder.IsDirectory()){UpdateLog(_T(忽略文件夹或点文件: ) finder.GetFilePath());continue;}CString strFilePath finder.GetFilePath();UpdateLog(_T(正在处理文件: ) strFilePath);CImage image;HRESULT hr image.Load(strFilePath);if (FAILED(hr)){UpdateLog(_T(加载图像失败: ) strFilePath);continue;}UpdateLog(_T(成功加载图像: ) strFilePath);// 示例处理转换为灰度图像for (int y 0; y image.GetHeight(); y){for (int x 0; x image.GetWidth(); x){COLORREF color image.GetPixel(x, y);BYTE gray BYTE(0.299 * GetRValue(color) 0.587 * GetGValue(color) 0.114 * GetBValue(color));image.SetPixel(x, y, RGB(gray, gray, gray));}}UpdateLog(_T(成功处理图像像素: ) strFilePath);// 构建新的文件路径CString fileName finder.GetFileName();CString newFilePath resultFolderPath _T(\\) fileName;hr image.Save(newFilePath);if (FAILED(hr)){UpdateLog(_T(保存图像失败: ) newFilePath);}else{UpdateLog(_T(处理并保存了图像: ) newFilePath);}}AfxMessageBox(_T(恭喜图像处理完成), MB_OK | MB_ICONINFORMATION);
}void CMFCApplicationImageDealDlg::UpdateLog(const CString message)
{// 将日志信息追加到log.txt文件中std::ofstream logFile;logFile.open(log.txt, std::ios_base::app); // 以追加模式打开文件if (logFile.is_open()){CT2CA pszConvertedAnsiString(message);std::string strStd(pszConvertedAnsiString);logFile strStd std::endl;logFile.close();}else{// 如果无法打开日志文件可以在这里处理错误AfxMessageBox(_T(无法打开日志文件进行写入。), MB_OK | MB_ICONERROR);}
}
此时运行项目就会出现如下界面 为了将图像处理过程独立出来作为一个单独的函数方便复用和代码维护。而且图像处理逻辑可能会在其他地方用到因此我们将其放在一个类中【例如一个“工具类”或者专门处理图像的类】。
因此我们需要创建一个新的.cpp文件【例如MyImageProcessing.cpp】并在相应的头文件MyImageProcessing.h中声明这个函数这样做的目的是可以保持代码的清晰和模块化。 增加代码
//MyImageProcessing.h
#pragma once
#include atlimage.h // 使用 CImage 类class MyImageProcessing
{
public:static HRESULT ConvertToGrayscale(CImage image);
};增加代码
// MyImageProcessing.cpp
#include MyImageProcessing.hHRESULT ImageProcessing::ConvertToGrayscale(CImage image)
{for (int y 0; y image.GetHeight(); y){for (int x 0; x image.GetWidth(); x){COLORREF color image.GetPixel(x, y);BYTE gray BYTE(0.299 * GetRValue(color) 0.587 * GetGValue(color) 0.114 * GetBValue(color));image.SetPixel(x, y, RGB(gray, gray, gray));}}return S_OK;
}然后在OnBnClickedButtonProcess函数中调用这个新函数
// MFCApplicationImageDealDlg.cpp: 实现文件
//#include pch.h
#include framework.h
#include MFCApplicationImageDeal.h
#include MFCApplicationImageDealDlg.h
#include afxdialogex.h
#include atlimage.h // 用于处理图像
#include fstream
#include MyImageProcessing.h#ifdef _DEBUG
#define new DEBUG_NEW
#endif// 用于应用程序“关于”菜单项的 CAboutDlg 对话框class CAboutDlg : public CDialogEx
{
public:CAboutDlg();// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD IDD_ABOUTBOX };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 实现
protected:DECLARE_MESSAGE_MAP()
};CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);
}BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()// CMFCApplicationImageDealDlg 对话框CMFCApplicationImageDealDlg::CMFCApplicationImageDealDlg(CWnd* pParent /*nullptr*/): CDialogEx(IDD_MFCAPPLICATIONIMAGEDEAL_DIALOG, pParent)
{m_hIcon AfxGetApp()-LoadIcon(IDR_MAINFRAME);
}void CMFCApplicationImageDealDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_BUTTON_FOLDER, m_btnSelectFolder);DDX_Control(pDX, IDC_BUTTON_PROCESS, m_btnProcess);DDX_Control(pDX, IDC_STATIC_DIRECTORY, m_staticDirectory);DDX_Control(pDX, IDC_EDIT_DIRECTORY, m_editDirectory);
}BEGIN_MESSAGE_MAP(CMFCApplicationImageDealDlg, CDialogEx)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON_FOLDER, CMFCApplicationImageDealDlg::OnBnClickedButtonFolder)ON_BN_CLICKED(IDC_BUTTON_PROCESS, CMFCApplicationImageDealDlg::OnBnClickedButtonProcess)
END_MESSAGE_MAP()// CMFCApplicationImageDealDlg 消息处理程序BOOL CMFCApplicationImageDealDlg::OnInitDialog()
{CDialogEx::OnInitDialog();// 将“关于...”菜单项添加到系统菜单中。// IDM_ABOUTBOX 必须在系统命令范围内。ASSERT((IDM_ABOUTBOX 0xFFF0) IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX 0xF000);CMenu* pSysMenu GetSystemMenu(FALSE);if (pSysMenu ! nullptr){BOOL bNameValid;CString strAboutMenu;bNameValid strAboutMenu.LoadString(IDS_ABOUTBOX);ASSERT(bNameValid);if (!strAboutMenu.IsEmpty()){pSysMenu-AppendMenu(MF_SEPARATOR);pSysMenu-AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 设置此对话框的图标。 当应用程序主窗口不是对话框时框架将自动// 执行此操作SetIcon(m_hIcon, TRUE); // 设置大图标SetIcon(m_hIcon, FALSE); // 设置小图标// TODO: 在此添加额外的初始化代码return TRUE; // 除非将焦点设置到控件否则返回 TRUE
}void CMFCApplicationImageDealDlg::OnSysCommand(UINT nID, LPARAM lParam)
{if ((nID 0xFFF0) IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialogEx::OnSysCommand(nID, lParam);}
}// 如果向对话框添加最小化按钮则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序
// 这将由框架自动完成。void CMFCApplicationImageDealDlg::OnPaint()
{if (IsIconic()){CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_castWPARAM(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon GetSystemMetrics(SM_CXICON);int cyIcon GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(rect);int x (rect.Width() - cxIcon 1) / 2;int y (rect.Height() - cyIcon 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);}else{CDialogEx::OnPaint();}
}//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplicationImageDealDlg::OnQueryDragIcon()
{return static_castHCURSOR(m_hIcon);
}void CMFCApplicationImageDealDlg::OnBnClickedButtonFolder()
{CFolderPickerDialog folderDlg;if (folderDlg.DoModal() IDOK){m_selectedFolderPath folderDlg.GetPathName();m_editDirectory.SetWindowText(m_selectedFolderPath);UpdateLog(_T(已选择的文件夹: ) m_selectedFolderPath);}
}void CMFCApplicationImageDealDlg::OnBnClickedButtonProcess()
{UpdateLog(_T(正在处理文件夹: ) m_selectedFolderPath);// 创建保存处理后图像的文件夹路径CString resultFolderPath m_selectedFolderPath _T(\\result);if (!CreateDirectory(resultFolderPath, NULL) GetLastError() ! ERROR_ALREADY_EXISTS)//如果文件夹创建成功或已存在【文件夹创建失败是因为已经存在】程序继续执行后续操作//否则【文件夹创建失败且不是因为已经存在的原因】程序会显示错误信息并停止处理。{AfxMessageBox(_T(无法创建处理后的图像文件夹), MB_OK | MB_ICONERROR);return;}// 图像处理逻辑CFileFind finder; // 创建一个 CFileFind 对象用于查找文件// CFileFind 是 MFC 提供的类用于在目录中查找文件。// 设置要查找的文件路径和模式CString strWildcard(m_selectedFolderPath); // 初始化查找路径为用户选择的文件夹路径strWildcard _T(\\*.jpg); // 在路径后面添加通配符 *.jpg 以查找所有 JPG 图像文件// 开始查找文件BOOL bWorking finder.FindFile(strWildcard); // 使用通配符查找文件返回查找的初始状态UpdateLog(_T(查找文件的初始状态: ) CString(bWorking ? _T(TRUE) : _T(FALSE))); // 记录初始查找状态while (bWorking){bWorking finder.FindNextFile(); //在调用 finder.FindFile 后finder.FindNextFile仍然遵循最初设定的查找模式//例如* .jpg并会继续查找该目录下的下一个符合模式的文件。UpdateLog(_T(bWorking 状态: ) CString(bWorking ? _T(TRUE) : _T(FALSE)));// 打印第一次调用 FindFile 找到的文件路径if (bWorking) {CString scenondFilePath finder.GetFilePath();UpdateLog(_T(第2次找到的文件路径: ) scenondFilePath);}if (finder.IsDots() || finder.IsDirectory()){UpdateLog(_T(忽略文件夹或点文件: ) finder.GetFilePath());continue;}CString strFilePath finder.GetFilePath();UpdateLog(_T(正在处理文件: ) strFilePath);CImage image;HRESULT hr image.Load(strFilePath);if (FAILED(hr)){UpdateLog(_T(加载图像失败: ) strFilePath);continue;}// 示例处理转换为灰度图像hr MyImageProcessing::ConvertToGrayscale(image); // 调用独立的图像处理函数if (FAILED(hr)){UpdateLog(_T(处理图像失败: ) strFilePath);continue;}// 构建新的文件路径CString fileName finder.GetFileName();CString newFilePath resultFolderPath _T(\\) fileName;hr image.Save(newFilePath);if (FAILED(hr)){UpdateLog(_T(保存图像失败: ) newFilePath);}else{UpdateLog(_T(处理并保存了图像: ) newFilePath);}}AfxMessageBox(_T(恭喜图像处理完成), MB_OK | MB_ICONINFORMATION);
}void CMFCApplicationImageDealDlg::UpdateLog(const CString message)
{// 将日志信息追加到log.txt文件中std::ofstream logFile;logFile.open(log.txt, std::ios_base::app); // 以追加模式打开文件if (logFile.is_open()){CT2CA pszConvertedAnsiString(message);std::string strStd(pszConvertedAnsiString);logFile strStd std::endl;logFile.close();}else{// 如果无法打开日志文件可以在这里处理错误AfxMessageBox(_T(无法打开日志文件进行写入。), MB_OK | MB_ICONERROR);}
}