从现在开始,我们将以基于对话框的MFC应用程序来讲解MFC应用
向导生成基于对话框MFC应用程序
对话框是一种特殊类型的窗口,绝大多数Windows程序都通过对话框与用户进行交互。在Visual C++中,对话框既可以单独组成一个简单的应用程序,又可以成为文档/视图结构程序的资源。
创建流程
项目属性修改:
1.属性->C/C++/代码生成/运行库->MTD ,Spectre缓解->禁用,
2.属性->高级->MFC的使用->在静态库中使用MFC
资源视图
查找方法一:
查找方法二:
在 MFC中,与用户进行交互的对话框界面被认为是一种资源。
这些资源只是一个类似UI文件的东西,只有外观而不具有功能,因此资源默认没有.h文件和.cpp文件关联。
基于对话框的MFC应用程序以窗口作为操作单位,当我们使用对话框等窗口时,需要为其添加类,以便我们以面向对象的方式处理窗口的行为。静态文本等控件是窗口的组成部分,也就是窗口类的成员,所以当我们使用控件时,需要为控件绑定变量,这使得我们可以通过变量来操作控件。
Dialog中存储的是对话框界面的ID,当我们双击ID时,对话框设计界面就会显示出来。
注意:ID为每个控件的唯一标识
这是ID为IDD_ABOUTBOX的对话框设计界面
这是ID为IDD_DIALOG_DIALOG的对话框设计界面,这是我们MFC程序默认生成的对话框
类视图
在类视图中,可以看到向导生成了3 个类:CAboutDlg,CDialogApp和CDialogDlg。
1.CAboutDlg:向导生成的关于版本信息对话框类。
2.CDialogApp:应用程序类,从 CWinApp 继承过来,封装了初始化、运行、终止该程序的代码。
3.CDialogDlg:对话框类,从CdialogEx继承过来的,在程序运行时看到的对话框就是它的一个具体对象。
在CDialogDlg对话框类中存在以下两个重要的函数:
1.DoDataExchange函数:该函数主要完成对话框数据的交换和校验。
2.OnInitDialog函数:对话框初始化处理函数
设计界面和工具箱
我们可以将工具箱中的工具拖入对话框中进行设计对话框
对话框属性修改
我们通过此方便找到了对话框的属性页,在这里进行对话框属性进行修改,这比使用代码修改方便的多
我们通过修改对话框属性页的描述文字修改了对话框的名字
注意:通过属性页修改属性的方法适用于所有的控件
对话框
对话框简介
本文使用基于对话框的MFC应用程序,MFC由C++封装而成,因此每个对话框在使用的时候需要为其添加类
对话框分为模态对话框和非模态对话框两种形式
模态对话框是一种会阻塞父窗口操作的对话框,当模态对话框弹出时,用户必须先对其进行操作,完成或关闭该对话框后才能继续与父窗口或其他窗口进行交互。
非模态对话框是不会阻塞父窗口操作的对话框,用户可以在不关闭该对话框的情况下继续与父窗口或其他窗口进行交互。
对话框应用
本应用实现通过点击不同的按钮弹出相应的对话框
步骤一:通过工具箱在界面上放两个个Button
我们清空了该对话框中的默认控件,然后通过工具栏添加了两个按钮并通过属性页修改了它的名字。我们同样也可以直接点击按钮然后打字修改名字
步骤二:添加两个对话框
资源视图 -> Dialog -> 右击 -> 插入
点击插入即可添加一个对话框
如图便是我们添加的两个对话框。
步骤三:使模态对话框关联类
点击对话框模板 -> 右击 -> 添加类
类视图中多了一个自定义类CDlgExec
在CDlgExec.h文件中,通过此方式将模态对话框与类关联
步骤四:按钮处理函数创建对话框,以模态方式运行
如下有四种方式生成处理函数
方法一:
方法二:
注意该按钮在哪个对话框,就要把他放在相应对话框的类里。
方法三:
直接双击按钮,VS便自动为我们生成了事件,但这种方式只能生成单击事件
方法四:
这是生成的处理函数
步骤五:弹出模态对话框
当处理函数需要使用别的控件,如对话框时,需要把它所属的类的头文件包含在定义事件的.cpp文件中
实现模态对话框的创建需要调用CDialog类的成员函数CDialog::DoModel,该函数的功能就是创建并显示一个对话框
步骤六:使非模态对话框关联类
在CDlgShow.h文件中,通过此方式将模态对话框与类关联
步骤七:添加非模态对话框按钮点击事件
步骤八:弹出非模态对话框
CDioalog.h类中声明对话框对象
在CDioalog.cpp中引用DlgShow.h
放在主对话框类的构造函数中创建非模态对话框,目的只创建一次对话框
定义事件处理函数
完成以上步骤以后,运行程序,我们点击模态对话框按钮就会弹出模态对话框,点击非模态对话框按钮弹出非模态对话框。
静态文本
静态文本简介
静态文本框是最简单的控件,它主要用来显示文本信息,不能接受用户输入,一般不需要连接变量,也不需要处理消息。
静态文本框的重要属性有:
1.ID:所有静态文本框的缺省ID都是IDC_STATIC,静态ID,不响应任何消息(事件)
2.Caption:修改显示的内容
常用接口:
接口 | 功能 |
CWnd::SetWindowText | 设置控件内容 |
CWnd::GetWindowText | 获取控件内容 |
CStatic::SetBitmap | 设置位图(后缀为bmp的图片) |
在属性中可修改静态文本的文字,也可点击静态文本控件直接写内容
静态文本应用一
当点击呵呵按钮时,静态文本变成呵呵,当点击获取按钮时,弹窗显示静态文本内容内容
关联控件变量:
静态文本等控件需要绑定变量是为了在我们实现点击按钮的功能时,能够找到该控件对象,然后实现相关功能
注意:XXX_STATIC形式ID为静态ID,不能关联变量。因此当我们需要给静态文本添加变量时,需要把ID修改,再关联变量:
此时,CStaticText.cpp便实现了静态文本控件和变量的关联:ID和变量名绑定
实现按钮设置功能:双击设置按钮进入处理函数
实现按钮显示功能:双击显示按钮进入处理函数
此时运行程序,点击按钮便正常设计和显示了
静态文本应用二
利用静态文本显示图片,只能显示位图(后缀.bmp)
一.将要显示的位图放置当前mfc项目所在的文件夹下:1.bmp
二.将该静态文本添加变量m_label,以便能够控制该文本
三.在目标窗口初始化函数中进行初始化
按钮
按钮简介
按钮是最常见的、应用最广泛的一种控件。按钮一般用于在程序执行期间,当单击某个按钮后就会执行相应的消息处理函数。按钮的主要属性是Caption,来设置在按钮上显示的文本。
常用接口:
接口 | 功能 |
CWnd::SetWindowText | 设置控件内容 |
CWnd::GetWindowText | 获取控件内容 |
CWnd::EnableWindow | 设置控件是否变灰 |
命令按钮处理的最多的消息是:BN_CLICKED,双击按钮即可跳转到处理函数。或者通过按钮属性 -> 控制事件 -> 选择所需事件,添加处理函数
应用
点击按钮修改按钮内容并弹窗显示内容
添加按钮事件处理函数
关联按钮控件变量
实现事件处理函数
编辑框
编辑框简介
MFC控件绑定变量由两种方式:值类型和控件类型,编辑框一般绑定值类型
常用属性设置:
属性 | 含义 |
Number | True只能输入数字 |
Password | True密码模式 |
Want return | True接收回车键,自动换行,只有在多行模式下,才能换行 |
Multiline | True多行模式 |
Auto VScroll | True 当垂直方向字符太多,自动出现滚动条,同时设置Vertical Scroll才有效 |
Vertical Scroll | True当垂直方向字符太多,自动出现滚动条,和Auto VScroll配合使用 |
Horizontal Scroll | True当垂直方向字符太多,自动出现滚动条,和Auto HScroll配合使用 |
Read Only | True 只读 |
常用接口:
接口 | 功能 |
CWnd::SetWindowText | 设置控件内容 |
CWnd::GetWindowText | 获取控件内容 |
应用一
我们将实现在上面的编辑框输入内容点击copy按钮,下方的编辑框出现相同内容。点击clos按钮窗口关闭
上方编辑框关联控件变量
下方编辑框关联控件变量
在主对话框类OnInitDialog()中,对上方的编辑框设置默认内容
注意:任何控件初始化都在主对话框类中OnInitDialog函数进行初始化
定义copy按钮事件处理函数
定义close按钮事件处理函数
小插曲
当我们设置一个普通的编辑框时,在该编辑框点击回车键时,窗口会关闭,这时是窗口的行为而非编辑框的行为。
为解决该问题,我们需要重写窗口的onOK处理函数
此时当我们在普通的编辑框点击回车键时,窗口不会再退出了
应用二
编辑框绑定值类别变量,点击设置按钮可以设置编辑框的内容,点击获取按钮获取编辑框的内容。
1.编辑框绑定变量:值类别CString类型变量。
编辑框添加了一个值类别的变量,则该变量就表示这个编辑框,编辑框中显示的内容就是变量的值。
2.实现设置按钮事件处理函数
3.实现获取按钮事件处理函数
应用三
实现点击读按钮,编辑框显示文件内容。点击写按钮,编辑框内容写入文件。点击查询按钮,编辑框显示目标文件内容
1.编辑框添加变量
2.代码实现读写按钮事件处理函数
此时,点击读按钮,编辑框显示文件内容
3.代码实现写按钮事件处理函数
4.代码实现查询按钮事件处理函数
传统方式
新型方式
下拉框
下拉框简介
常用属性设置:
属性 | 含义 |
data | 设置内容,不同内容间用英文的分号“;”分隔 |
type | 显示风格 |
Sort | True 内容自动排序 |
常用接口:
接口 | 功能 |
CComboBox::AddString | 组合框添加一个字符串 |
CComboBox::SetCurSel | 设置当前选择项(当前显示第几项),下标从0开始 |
CComboBox::GetCurSel | 获取组合框中当前选中项的下标 |
CComboBox::GetLBText | 获取指定位置的内容 |
CComboBox::DeleteString | 删除指定位置的字符串 |
CComboBox::InsertString | 在指定位置插入字符串 |
下拉框的内容可通过属性页中数据项进行设置
应用一
下拉框并不作为功能实现,而是形式存在
代码实现下拉框中值的添加
1.添加变量
2.在主对话框中进行初始化
应用二
在下拉框属性页控件事件中有一CBN_SELCHANGE事件,当切换下拉框选项时,可以触发该事件。现我们利用该事件,使得切换下拉框选项时可以弹窗显示选项内容
菜单
1.添加菜单资源:
如图便是我们创建的菜单,ID为IDR_MENU1
2.主对话框绑定菜单
此时运行程序便有了菜单
应用
点击菜单项3弹窗
1.添加菜单项3事件处理函数
2.代码实现时间处理函数
列表
列表简介
常用属性设置:view -> Report(报表方式)
常用接口:
接口 | 功能 |
CListCtrl::SetExtendedStyle | 设置列表风格 |
CListCtrl::GetExtendedStyle | 获取列表风格 |
CListCtrl::InsertColumn | 插入某列内容,主要用于设置标题 |
CListCtrl::InsertItem | 在某行插入新项内容 |
CListCtrl::SetItemText | 设置某行某列的子项内容 |
CListCtrl::GetItemText | 获取某行某列的内容 |
应用一
接下来我们将对这个列表填充内容
1.添加变量
2.列表初始化
应用二
实现一个目录文件显示器,此处列表为report视图
1.添加变量
2.列表初始化
3.添加菜单
获取文本:弹窗选中行0列文本,并修改文本
删除一行:删除选中行数据
删除全部:删除全部数据
4.添加列表右键事件处理函数
5.添加菜单选项事件处理函数
树
树简介
常用属性设置:
属性 | 含义 |
has buttons | True 有展开按钮 |
has lines | True 有展开线 |
lines at root | True 有根节点 |
常用接口:
接口 | 功能 |
AfxGetApp() | 获取应用程序对象指针 |
CWinApp::LoadIcon | 加载自定义图标 |
CImageList::Create | 创建图像列表 |
CImageList::Add | 图像列表追加图标 |
CTreeCtrl::SetImageList | 设置图形状态列表 |
CTreeCtrl::InsertItem | 插入节点 |
CTreeCtrl::SelectItem | 设置默认选中项 |
CTreeCtrl::GetSelectedItem | 获取选中项 |
CTreeCtrl::GetItemText | 获取某项内容 |
应用一
将上述树控件初始化为下图所示:
1.关联控件变量
2.把ico资源文件放在项目所在文件夹的res文件夹中
3.对话框添加图标资源(.icon)
4.在对话框头文件中保存图像列表
5.代码初始化树控件
应用二
实现点击节点弹窗的功能
树控件常用事件为:TVN_SELCHANGED,当切换某个节点时,自动触发此事件。
此时,我们点击树节点就会弹窗显示内容。
注意:由于我们在上文设置了树的默认节点,因此当我们运行程序窗口实现前会先弹窗节点的内容
应用三
点击当前选中按钮弹窗弹窗显示当前节点内容并进行修改内容
点击删除选中删除当前节点
点击全部删除按钮清空所有节点
1.添加树变量
2.初始化树控件
3.实现当前选中按钮单击处理事件函数
4.实现当前删除按钮单击处理事件函数
5.实现全部删除按钮单击处理事件函数
标签页
标签页简介
标签页可依赖于主对话框切换对话框,而非弹窗切换对话框
应用一
切换标签页时切换不同的对话框
1.标签页添加变量
2.使用标签页时需要引用外部文件TabSheet.cpp和TabSheet.h(MSDN下载),将这两个文件放置到在项目文件同级目录,并且添加到工程目录中
3.每个标签页都对应一个对话框,我们使用两个标签页因此需要在资源中添加两个对话框
属性页修改:样式:child,边框:None
4.给每个添加的对话框添加类
5.主对话框.h文件中, 定义自定义类对象,需要相应头文件
6.主对话框.cpp文件添加头文件并实现代码
此时运行程序便可通过标签页切换不同的对话框了
应用二
1.标签页添加变量
2.添加三个标签页,即对话框,并添加类
对话框属性:外观:None,样式:Child
对话框类名依次CPAGE1,CPAGE2,CPAGE3
3.主对话框.cpp文件包含三个对话框的头文件
4.主对话框.h文件创建三个对话框的对象
5.标签页在主对话框.cpp文件中初始化
6.实现切换页的事件处理函数
此时切换页就可以正常显示对话框了
进度条与滑块
简介
应用
实现点击进入按钮进度条加载,拉动滑块控制进度条进度
1.添加变量
进度条添加变量
滑块添加变量
2.代码初始化滑块和进度条
3.代码实现进度按钮处理函数
4.代码实现滑块控制进度条功能
单选按钮
应用一
点击获取按钮弹窗显示选中的单选按钮
1.为按钮1,2,3分别添加变量m_Bn1,m_Bn2,m_Bn3
2.代码实现获取按钮事件处理函数
应用二
点击任意单选按钮为单选按钮4赋值,点击获取按钮弹窗单选按钮4的值
1.为按钮4,5,6分别添加值类别变量m_Bn4,m_Bn5,m_Bn6
2.代码实现单选按钮及获取按钮的事件处理函数
IP控件
IP 控件:用于让用户输入和显示 IP 地址的可视化控件
现针对以上功能进行应用实现
应用一
点击设置按钮设置IP地址
1.IP控件添加变量
2.代码实现设置按钮点击处理事件
应用二
点击清除按钮,清除设置的IP地址
添加清除按钮点击事件处理函数
应用三
点击获取按钮,将已知的的IP地址设置到IP控件中
添加获取按钮点击处理事件
作业
1.使用MFC搜索D盘获取指定文件并且读取到程序内,显示在列表上
初始化
m_List.InsertColumn(0, L"Path", 0, 400);
功能实现
CString RealFilePath = L"0";
CString FileFind(CString FilePath, CString FileName)
{CFileFind finder;FilePath = FilePath + L"\\*.*";BOOL bRet = finder.FindFile(FilePath);while (bRet){bRet = finder.FindNextFileW();if (finder.IsDots())//当遍历到特殊目录时跳过本次循环{continue;}CString strName = finder.GetFileName();CString strPath = finder.GetFilePath();if (finder.IsDirectory())//当目标文件是目录时{FileFind(strPath, FileName);}if (strName == FileName){RealFilePath = strPath;}}return RealFilePath;
}void CMFCApplication2Dlg::OnBnClickedButton1()
{CString FilePath = FileFind(L"D:", L"QQ浏览器截图20240814104659.png");m_List.InsertItem(0, FilePath, NULL);
}
2.自己随便写点什么,练习树控件的使用;
此处我们只是简单的实现了一个树的基本框架并没有实现相关功能
HTREEITEM hRoot1 = m_Tree.InsertItem(L"祖父", TVI_ROOT, TVI_LAST);HTREEITEM hRootSubNode1 = m_Tree.InsertItem(L"父亲", hRoot1, TVI_LAST);HTREEITEM hRootSubNodeSub1 = m_Tree.InsertItem(L"儿子", hRootSubNode1, TVI_LAST);HTREEITEM hRoot2 = m_Tree.InsertItem(L"祖母", TVI_ROOT, TVI_LAST);HTREEITEM hRootSubNode2 = m_Tree.InsertItem(L"母亲", hRoot2, TVI_LAST);HTREEITEM hRootSubNodeSub2 = m_Tree.InsertItem(L"女儿", hRootSubNode2, TVI_LAST);
3.模仿任务管理器,实现一个多Tab的程序
4.使用MFC搜索D盘获取指定文件并且读取到程序内,显示在Edit上
CString RealFilePath = L"0";
CString FileFind(CString FilePath, CString FileName)
{CFileFind finder;FilePath = FilePath + L"\\*.*";BOOL bRet = finder.FindFile(FilePath);while (bRet){bRet = finder.FindNextFileW();if (finder.IsDots())//当遍历到特殊目录时跳过本次循环{continue;}CString strName = finder.GetFileName();CString strPath = finder.GetFilePath();if (finder.IsDirectory())//当目标文件是目录时{FileFind(strPath, FileName);}if (strName == FileName){RealFilePath = strPath;}}return RealFilePath;
}void CMFCApplication2Dlg::OnBnClickedButton1()
{CString FilePath = FileFind(L"D:", L"QQ浏览器截图20240814104659.png");m_Edit.SetWindowTextW(FilePath);
}