MFC-第三节 基于对话框编程、常用控件
基于对话框编程
- 对话框是一种特殊类型的窗口,绝大多数Windows程序都通过对话框与用户进行交互。在Visual C++中,对话框既可以单独组成一个简单的应用程序,又可以成为文档/视图结构程序的资源。
创建基于对话框的 MFC 应用程序框架
-
选择“文件 新建 项目”菜单; - 在“新建项目”对话框中,选择“ MFC 应用程序 ”,输入工程名称(MFCDialog),选择“确定”。
- 应用程序类型:选择“ 基于对话框”,即创建基于对话框的应用程序,选择“完成
对话框应用程序框架介绍
- 资源视图
- 创建基于对话框的应用程序框架(假定工程名为 MFCDialog )后,项目工作区上增加了一个“资源视图”选项卡。或者,通过视图找到“资源视图”选项卡
- 点击该选项卡,展开项目目录,找到Dialog文件目录下会看到2个文件”IDD_ABOUTBOX”/”IDD_MFCDIALOG_DIALOG”
- 在 MFC中,与用户进行交互的对话框界面被认为是一种资源。
- ID为IDD_MFCDIALOG_DIALOG:
- 中间部分(MFCDIALOG)与项目名称相同,对应中间的对话框设计界面。不管在何时,只要双击对话框资源的ID,对话框设计界面就会显示在中间。
- IDD_ABOUTBOX:
- 关于对话框,用于说明当前应用程序的一些信息
- ID为IDD_MFCDIALOG_DIALOG:
- 运行demo,显示的视窗,就是IDD_MFCDIALOG_DIALOG资源,相当于iOS的sb,点击左上角的图标弹出系统菜单,点击”关于…“,弹出的就是关于对话框IDD_ABOUTBOX资源
- 右击IDD_MFCDIALOG_DIALOG资源,属性,找到Caption设置内容,这便是对话框的标题设置
- 类视图
- 在类视图中,可以看到生成了3 个类:CAboutDlg、CMFCDialogApp和CMFCDialogDlg。
- CAboutDlg:对应生成的版本信息对话框。
- CDialogApp:应用程序类,从 CWinApp 继承过来,封装了初始化、运行、终止该程序的代码。
- CDialogDlg:对话框类,从CdialogEx继承过来的,在程序运行时看到的对话框就是它的一个具体对象
- DoDataExchange函数:该函数主要完成对话框数据的交换和校验。
- OnInitDialog函数:相当于对对话框进行初始化处理。
- 在类视图中,可以看到生成了3 个类:CAboutDlg、CMFCDialogApp和CMFCDialogDlg。
- 工具箱:
- 视图->工具箱
- 各种控件用于丰富资源界面
模态对话框与非模态对话框
模态对话框
- 当模态对话框显示时,程序会暂停执行,直到关闭这个模态对话框之后,才能执行程序中的其他任务。
- 实现点击”模态对话框“按钮,则弹出一个模态对话框
- 主界面添加”模态对话框“按钮
- 通过工具箱在主界面上放一个Button,右击->属性,找到caption修改名字为模态对话框
- 双击此按钮即可跳转到按钮处理函数:会看到是在MFCDialogDlg.cpp文件中
- 除了双击,还有2种方法,添加点击按钮的实现
- 右击按钮->属性->点击右边的闪电图标(控件事件)->BN_CLICKED->右边的下来箭头Add…
- 右击按钮->添加事件处理程序->选择事件类型、修改处理程序名称->添加编辑即可
- 除了双击,还有2种方法,添加点击按钮的实现
- 添加模态对话框的资源视图
- 资源视图 -> Dialog -> 右击 -> 插入 Dialog:会看到资源视图的Dialog文件夹下多了一个IDD_DIALOG1资源视图
- 设置当前视图名称为”模态对话框“
- 修改对话框的ID,在属性中找到ID,修改为IDD_EXEC
- 当前模态对话框添加相应的类
- 点击对话框模板 -> 右击 -> 添加类:
- 设置类名(CDlgEexec)点击确定,即可
- 类视图中多了一个自定义类CDlgEexec:这个类就是与这个对话框关联的类
- 主界面按钮处理函数创建对话框,以模态方式运行。
- 实现模态对话框的创建需要调用CDialog类的成员函数CDialog::DoModel,该函数的功能就是创建并显示一个对话框:
- 在MFCDialogDlg.cpp文件中
- 导入CDlgEexec.h文件
- 找到”模态对话框“按钮相应函数
void CMFCDialogDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 CDlgEexec dlg; dlg.DoModal();//以模态的方式运行 }
- 主界面添加”模态对话框“按钮
非模态对话框
- 当非模态对话框显示时,运行转而执行程序中的其他任务,而不用关闭这个对话框
- 实现点击”非模态对话框“按钮,则弹出一个非模态对话框
- 图形界面操作过程和模态对话框一样,ID为IDD_SHOW,类名为CDlgShow
-
在CMFCDialogDlg类的成员函数中添加成员属性
// MFCDialogDlg.h: 头文件 #pragma once #include "CDlgShow.h" // CMFCDialogDlg 对话框 class CMFCDialogDlg : public CDialogEx { // 构造 public: ... // 实现 protected: ... //这个要保存到成员属性中强引用,否则就会释放掉 CDlgShow dlg; }; - 在OnInitDialog函数中create
- 这个方法就相当于iOS的viewDidLoad
// CMFCDialogDlg 消息处理程序 BOOL CMFCDialogDlg::OnInitDialog() { ... // TODO: 在此添加额外的初始化代码 //该方法不允许多次创建,只能创建一次,因此可以把它放在CMFCDialogDlg类的OnInitDialog函数中 dlg.Create(IDD_SHOW); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } -
实现非模态按钮点击方法
void CMFCDialogDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 //这个要保存到成员属性中强引用,否则就会释放掉 //CDlgShow dlg; //该方法不允许多次创建,只能创建一次,因此可以把它放在CMFCDialogDlg类的OnInitDialog函数中 //dlg.Create(IDD_SHOW); dlg.CenterWindow();//居中显示 dlg.ShowWindow(SW_SHOWNORMAL); }
常用控件
静态文本框CStatic
- 静态文本框是最简单的控件,它主要用来显示文本信息,不能接受用户输入,一般不需要连接变量,也不需要处理消息。
- 静态文本框的重要属性有:
- ID:所有静态文本框的缺省ID都是IDC_STATIC,静态ID,不响应任何消息(事件)
- Caption:修改显示的内容
-
常用的接口
CWnd::SetWindowText 设置控件内容 CWnd::GetWindowText 获取控件内容 CStatic::SetBitmap 设置位图(后缀为bmp的图片) - 关联变量(相当于iOS的脱线成属性)
- 由于XXX_STATIC静态ID是不能关联变量,故需把ID修改后,再关联变量:右击属性,修改ID:IDC_STATICLabel
- 右击->添加变量,设置变量名、访问类型,点击确定即可(m_text)
- 就可以在当前主窗口类中生成一个成员变量
-
代码示例:
void CMy01staticTextDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 //设置文本 m_text.SetWindowTextW(TEXT("hhhh")); } void CMy01staticTextDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 //获取当前的文本 CString str; m_text.GetWindowTextW(str); MessageBox(str); }
- 显示bmp图片
- 将bmp图片复制到项目根目录下 1.bmp
- 在拖一个用来显示图片,修改ID,添加为成员变量,命名m_img
-
显示图片
//显示图片 //设置静态控件窗口风格为位图居中显示 m_img.ModifyStyle(0xf, SS_BITMAP | SS_CENTERIMAGE); //通过路径获取bitmap句柄 #define HBMP(filepath,width,height) (HBITMAP)LoadImage(AfxGetInstanceHandle(),filepath,IMAGE_BITMAP,width,height,LR_LOADFROMFILE|LR_CREATEDIBSECTION) //获取控件宽高 CRect rect; m_img.GetWindowRect(rect); //静态控件设置bitmap m_img.SetBitmap(HBMP(TEXT("./1.bmp"), rect.Width(), rect.Height()));
普通按钮 CButton
- 按钮是最常见的、应用最广泛的一种控件。在程序执行期间,当单击某个按钮后就会执行相应的消息处理函数。
- 按钮的主要属性是Caption,来设置在按钮上显示的文本。
- 命令按钮处理的最多的消息是:BN_CLICKED,双击按钮即可跳转到处理函数。或者,通过按钮属性 -> 控制事件 -> 选择所需事件,添加处理函数:
-
常用接口:
CWnd::SetWindowText 设置控件内容 CWnd::GetWindowText 获取控件内容 CWnd::EnableWindow 设置控件是否变灰 - 关联控件变量:跟CStatic一样
编辑框CEdit
-
常用属性设置:
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 获取控件内容 - 关联控件变量
- 同上
- 关联基本类型变量
- 右击该控件->添加变量
- 变量类型:选择适合的类型
- 变量名:自己定义
- 类别:
- 控件(control):默认
- value(值)
- 若一个编辑框连接了一个Value类别的变量,则该变量就表示这个编辑框中显示的内容就是变量的值。
- 但是,改变了编辑框的内容并不会自动更新对应的变量的值,同样,改变了变量的值也不会自动刷新编辑框的内容。若要保持一致,需要使用UpdateData()函数更新:
- 若编辑框的内容改变了,则应使用语句UpdateData(TRUE) 获取对话框数据
- 若变量的值改变了,则应使用语句UpdateData(FALSE) 初始化对话框控件
- 右击该控件->添加变量
- 代码示例:(变量类别选择为“值(value)”类型。)
- 回车退出: 该对话框运行起来,输入内容,然后回车,就会返现程序会退出
- 解决:将属性Multiline 改为ture
- 点击回车,自动换行
- 将属性Want return设置为ture
- 横向、纵向无限输入:当输入内容超过默认大小时,自动滚动输入 Auto VScroll、Auto HScroll,设置为true
-
代码:
void CMy02EditTestDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 //点击copy按钮,将edit1的内容粘贴到edit2中 CString str; m_edit1.GetWindowTextW(str); m_edit2.SetWindowTextW(str); } //退出当前窗口 void CMy02EditTestDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 //点击“close”关闭应用程序 //退出整个程序 //exit(0); //退出当前对话框 //以确定的方式退出 //CDialogEx::OnOK(); //以取消的方式退出 CDialogEx::OnCancel(); } //设置edit3 //注意:edit3是以值(value)的类型关联的成员变量 void CMy02EditTestDlg::OnBnClickedButton3() { // TODO: 在此添加控件通知处理程序代码 //设置edit3,会发现没有GetWindowTextW方法 m_edit3 = TEXT("hhhhh"); //将变量同步到控件上 UpdateData(FALSE); } //获取edit3内容 void CMy02EditTestDlg::OnBnClickedButton4() { // TODO: 在此添加控件通知处理程序代码 //将控件内容同步到变量中 UpdateData(TRUE); MessageBox(m_edit3); }
- 回车退出: 该对话框运行起来,输入内容,然后回车,就会返现程序会退出
组合框(下拉框) CComboBox
-
常用属性设置:
data 设置内容,不同内容间用英文的分号“;”分隔 type 显示风格 Sort True 内容自动排序 -
常用接口:
CComboBox::AddString 组合框添加一个字符串 CComboBox::SetCurSel 设置当前选择项(当前显示第几项),下标从0开始 CComboBox::GetCurSel 获取组合框中当前选中项的下标 CComboBox::GetLBText 获取指定位置的内容 CComboBox::DeleteString 删除指定位置的字符串 CComboBox::InsertString 在指定位置插入字符串 -
使用:
- 拖一个CComboBox,右击属性设置data:可乐;雪碧;经典
- 运行程序会发现顺序不是设置的顺序,主要原因是属性中的sort的原因,设置为false即可
-
默认框中是可以输入内容的,但是不想让输入,使用type属性,设置为“下拉列表”即可
// CMy03commonboxDlg 消息处理程序 BOOL CMy03commonboxDlg::OnInitDialog() { ... // TODO: 在此添加额外的初始化代码 //对下拉框添加数据 m_cbx.AddString(TEXT("郑州")); m_cbx.AddString(TEXT("北京")); m_cbx.AddString(TEXT("南京")); //设置默认值 m_cbx.SetCurSel(2); //删除某项 m_cbx.DeleteString(0); //插入数据 m_cbx.InsertString(2, TEXT("成都")); //根据索引查找内容 /*CString str; m_cbx.GetLBText(2, str); MessageBox(str);*/ return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } - 选择某个item的事件监听
- 组合框常用的事件为:CBN_SELCHANGE,当选择组合框某一项时,自动触发此事件。
- 右击CComboBox控件,属性->点击闪电(事件),找到 CBN_SELCHANGE,会看见响应函数已经实现
OnCbnSelchangeCombo1。 -
找到该函数实现
void CMy03commonboxDlg::OnCbnSelchangeCombo1() { // TODO: 在此添加控件通知处理程序代码 //获取到当前索引 int index = m_cbx.GetCurSel(); //拿到内容 CString str; m_cbx.GetLBText(index, str); //弹出选择的内容 MessageBox(str); }
列表控件 CListCtrl
- 常用属性设置:view -> Report(报表方式)
-
常用接口:
CListCtrl::SetExtendedStyle 设置列表风格 CListCtrl::GetExtendedStyle 获取列表风格 CListCtrl::InsertColumn 插入某列内容,主要用于设置标题 CListCtrl::InsertItem 在某行插入新项内容 CListCtrl::SetItemText 设置某行某列的子项内容 CListCtrl::GetItemText 获取某行某列的内容 - 使用
- 拖一个listctrl注意不是listbox
- 右击属性->view,里面有很多样式,选择report
-
关联变量
// CMy05listtestDlg 消息处理程序 BOOL CMy05listtestDlg::OnInitDialog() { ... // TODO: 在此添加额外的初始化代码 //listctrl初始化 //插入表头 //插入列头 CString str[3] = { TEXT("姓名"),TEXT("性别"),TEXT("年龄") }; for (int i = 0; i < 3; i++) { //索引、内容、宽度 m_list.InsertColumn(i, str[i],LVCFMT_LEFT,100); } //设置正文 ////设置张三行 //m_list.InsertItem(0, TEXT("张三")); //m_list.SetItemText(0, 1, TEXT("男")); //m_list.SetItemText(0, 2, TEXT("18")); for (int i = 0; i < 10; i++) { int j = 0; CString name; name.Format(TEXT("张三 %d"), i); m_list.InsertItem(i, name); m_list.SetItemText(i, ++j, TEXT("男")); m_list.SetItemText(i, ++j, TEXT("18")); } //设置风格样式 //LVS_EX_GRIDLINES 网格 //LVS_EX_FULLROWSELECT 选中整行 m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT ); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE }
树控件 CTreeCtrl
-
常用属性设置:
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 获取某项内容 -
使用
- 拖一个CTreeCtrl控件
- 设置常用属性:
- 属性has lines设置为true展开则有线连接
- 属性has buttons 设置为true 每级有按钮
- 属性lines at root True 根节点之前也有线
- 添加为成员变量m_tree
- 添加图片资源
- 打开项目根目录->res文件夹->打开,将图片资源复制进去,图片资源为ico结尾
- 导入图片资源:
- 打开“资源视图”有个icon目录文件夹
- 右击Icon->添加资源->icon->导入->打开res文件夹->选中刚才所有导入的图片资源->打开,即将所有的资源导入了
-
初始化方法中添加初始化CTreeCtrl控件
// TODO: 在此添加额外的初始化代码 //使用 //1. 设置资源 //1.1手动导入图片资源 //1.2准备HICON HICON icon[4]; //IDI_ICON1为导入图片资源的ID icon[0] = AfxGetApp()->LoadIconW(IDI_ICON1); icon[1] = AfxGetApp()->LoadIconW(IDI_ICON2); icon[2] = AfxGetApp()->LoadIconW(IDI_ICON3); icon[3] = AfxGetApp()->LoadIconW(IDI_ICON4); //放到成员属性中 /*CImageList list;*/ //1.3准备list图标的集合 list.Create(30, 30, ILC_COLOR32, 4, 4); //1.4 加载图片 for (int i = 0; i < 4; i++) { list.Add(icon[i]); } //list.Add() m_tree.SetImageList(&list,TVSIL_NORMAL); //2. 设置节点 //参数:结点名/默认图片/选中图片/父节点 HTREEITEM rootitem = m_tree.InsertItem(TEXT("根节点"),0,0,NULL); HTREEITEM partentitem = m_tree.InsertItem(TEXT("父节点"), 1, 1, rootitem); HTREEITEM sub1item = m_tree.InsertItem(TEXT("子节点1"), 2, 2, partentitem); HTREEITEM sub2item = m_tree.InsertItem(TEXT("子节点2"), 3, 3, partentitem); //3. 设置默认选中节点 m_tree.SelectItem(sub1item); - 点击每个结点,事件监听
- 树控件常用事件为:TVN_SELCHANGED,当选择某个节点时,自动触发此事件。
-
在属性、事件列表中找到该事件,然后右击添加,定位到函数
void CMy06treectrolDlg::OnTvnSelchangedTree1(NMHDR *pNMHDR, LRESULT *pResult) { LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); // TODO: 在此添加控件通知处理程序代码 //获取当前选中的行 HTREEITEM item = m_tree.GetSelectedItem(); //根据当前选中的行,获取内容 CString str = m_tree.GetItemText(item); MessageBox(str); *pResult = 0; }
标签控件 CTabCtrl
- 功能实现:一个tab2个item:系统消息、系统设置,点击相应的item,显示相应的视窗
- 拖入一个CTabCtrl控件
- 添加为成员变量,但是这个变量继承自CTabSheet这个自定义的类
- 将TabSheet.h与.cpp复制到项目根目录下(这两个文件是自定义的CTabCtrl控件类CTabSheet)
- 右击项目,添加现有项目,分别把.h与.cpp加入
- 右击CTabCtrl控件->添加变量->变量类型修改为CTabSheet,命名为m_tab
- 插入2个DIALOG
- 右击Dialog,插入2个
- 修改这两个Dialog 属性,Border设置为None,style设置为child
- 分别拖一个Button一个为“系统消息”,一个为“系统设置”
- 分别为这两个Dialog添加类:Dialog1,Dialog2
-
主对话框中导入头文件,添加成员变量
#include"TabSheet.h" #include"Dlg1.h" #include"Dlg2.h" // CMy08TBDlg 对话框 class CMy08TBDlg : public CDialogEx { ... public: CTabSheet m_tab; Dlg1 dlg1; Dlg2 dlg2; }; -
主对话框类中 OnInitDialog() 做初始化工作
// TODO: 在此添加额外的初始化代码 //dlg1.dlg2加载到tab中 m_tab.AddPage(TEXT("系统消息"), &dlg1, IDD_DIALOG1); m_tab.AddPage(TEXT("系统设置"), &dlg2, IDD_DIALOG2); //显示 m_tab.Show();