一、实验目的:
1、 熟悉 Windows 对话框应用程序开发的基本过程;
2、 学习标准控件的使用;
3、 学些 CommonDialog ActiveX 控件的使用;
4、 练习较复杂的交互式操作的控制流程;
5、 练习文件输入/输出流的使用。
二、实验内容
实现一个具有一定实用价值的通讯录程序设计。界面如图所示
三、 实验主要原理说明
①界面的基本设计
-
开发windows应用程序,往往是从界面开发开始。在资源视图中把对话框调出,把对话框中自带的控件删掉,放入自己所需要的控件。
-
先设立两个组合框Group Box(Group Box组合框会将组合框内的控件标识为一组控件来使用:只能选择其中的一个控件),将两个组合框属性中的描述文字分别改为:联系人、地址簿,便于用户区分。在联系人组合框中放入两组Static Text和Eidt Control分别表示姓名和电话号码,并再放一组Static Text和Combo Box(组合框控件:由一个文本输入控件和一个下拉菜单组成。用户可以从一个预先定义的列表里选择一个选项,同时也可以直接在文本框里输入文本。)表示用户可以选择的群组。Ctrl选中联系人里面的控件进行位置调整。
-
在对话框中放入六个Button控件,Ctrl选中这六个控件进行位置调整,并在属性中对这六个按钮的描述文字依次改成载入、保存、退出、新建、更新、删除,供用户进行使用。
-
在地址簿这个组合框中放入List Control控件(相当于一个表格),调整大小,在该控件的属性栏中,单选设置为True(表示用户只能选择该列表的一个元素)、视图设为Report(以报表的形式呈现给用户)、文本右对齐设为True、始终显示选定的内容设置为True、
-
为所有用户需要的控件进行ID修改,以便后面类向导给控件绑定变量时进行区分:
控件 ID 姓名Edit Control IDC_EDITNAME 号码Edit Control IDC_EDITNUMBER 群组Combo Box IDC_COMBOGROUP 载入Button IDC_BUTTONLOAD 保存 Button IDC_BUTTONSAVE 退出 Button IDC_BUTTONEXIT 新建 Button IDC_BUTTONNEW 更新 Button IDC_BUTTONUPDATA 删除 Button IDC_BUTTONDELETE 地址簿List Control IDC_LISTCONTROL -
插入ActiveX控件:Microsoft Common Dialog Control version6.0(这是一个共用控件,可以调用字体格式选择对话框,打开文件对话框,打印对话框,保存对话框,颜色选择框),该对话框对于用户来说是不可见的。在属性一栏中,将Filter设置为:文本文件(.txt)|.txt|所有文件(.)|.* 。下表是通用对话框的使用方法:
*方法* *所显示的对话框* *ShowOpen* 显示“打开”对话框 *ShowSave* 显示“另存为”对话框 *ShowColor* 显示“颜色”对话框 *ShowFont* 显示“字体”对话框 *ShowPrinter* 显示“打印”或“打印选项”对话框 *ShowHelp* 调用 Windows 帮助引擎 -
打开类向导,添加成员变量
控件ID 控件类型 类别 名称 访问 变量类型 IDC_COMBOGROUP COMBOBOX 值 m_sGroup public CString IDC_COMBOGROUP COMBOBOX 控件 m_ComboGroup public CComboBox IDC_COMMONDIALOG1 OCX 控件 FileDialog public COMMONDIALOG1 IDC_EDITNAME EDIT 值 m_sName pubilc CString IDC_EDITNAME EDIT 控件 m_EditName public CEdit IDC_EDITNUMBER EDIT 值 m_sNumber public CString IDC_LISTCONTROL SysListView32 控件 m_ListControl public CListCtrl CString、CComboBox、COMMONDIALOG1、CEdit、CString、CListCtrl这些变量类型都是MFC已经封装好的类,里面有对应的方法可以使用、查看。添加完这些成员变量之后,我们的项目中会有三个类被创建:COMMONDIALOG1、CExperiment3App、CExperiment3Dlg。界面的设计基本已经完成
②类的基本设计
-
将实验一中的代码拷贝到现在的项目中,进行复用(在头文件中添加address.h 在源文件中添加addresss.cpp)。
-
在Experiment3Dlg.h中添加头文件address.h ,即(#include “address.h”) ,并在CExperiment3Dlg.cpp、addressbook.cpp中添加头文件pch.h。(在MFC项目中所有的源文件前都必须含有pch.h这个头文件)
-
在Experiment3Dlg.h中除了之前用类向导添加的变量,另外添加AddressBook的实例book。
-
给用户操作的按钮:载入、保存、新建、更新、删除 都需要有对应的方法来对数据进行操作。另外,需要一个辅助函数对数据进行刷新。可以右键类Addressbook,选中添加函数,可快速添加函数。
方法对应的按钮 函数名 返回类型 访问 .cpp文件 参数 载入 LoadFile void public Addressbook.cpp CString Filename 保存 SaveFile void public Addressbook.cpp CString Filename 新建 AddContact void public Addressbook.cpp string 更新 Update void public Addressbook.cpp Int nstring namestring numberstring group 删除 Delete void public Addressbook.cpp Int n 辅助函数 RefreshData void public Addressbook.cpp bool fromDlgToVector 但这样操作也会产生相对应的问题:
如果Addressbook中存在名称为Delete的函数,即使我们添加的函数返回值和传入参数不一样,也不能添加名称为Delete的函数。需要自己手动添加。
Tip:由于涉及到读入文件,记得在源文件前加入fstream文件流(#include “fstream”)
对应的函数代码如下:
载入按钮:
void AddressBook::LoadFile(CString Filename) { // TODO: 在此处添加实现代码. ifstream inputFile; string Name, Number, Group; try { inputFile.open(Filename); Book.clear(); while (!inputFile.eof()) { inputFile >> Name >> Number >> Group; AddContact(Name, Number, Group); } } catch (exception& e) { throw(e); } }
保存按钮:
void AddressBook::SaveFile(CString Filename) { // TODO: 在此处添加实现代码. ofstream outputFile; string Name, Number, Group; try { outputFile.open(Filename); int Count = Book.size(); for (int index = 0 ; index < Count; index++) { if (index > 0) outputFile << endl; Book[index].getContact(Name, Number, Group); outputFile << Name << " " << Number << " " << Group; } } catch (exception& e) { throw(e); } }
删除按钮:
void AddressBook::Delete(int n) { if (n >= 0 && n < Book.size()) { vector<CContact>::iterator pos = Book.begin() +n ; Book.erase(pos); } }
更新按钮:
void AddressBook::Update(int n, string name, string number, string group) { if (n >= 0 && n < Book.size()) { Book[n].setContact(name,number,group); } }
③事件的基本设计
所谓事件设计,就相当于是界面设计(呈现给用户的操作方式)和类设计(对于数据的操作)中间的桥梁。
-
初始化过程
1). 对于地址簿(List Control)的初始化
地址簿对应的变量名为m_ListControl,变量类型为CListCtrl.
(CListCtrl是列表控件类,列表控件的每一行叫做一个item,每一列叫做一个subitem。每一行和每一列都有个ID号,可以确定唯一的单元格。)
该类中具有两个构建列表的方法:
m_pListCtrl->InsertColumn(0,"第一列");
列索引从0开始,InsertColumn函数将在列表中建立一个列,如果数据有三列,就调用三次此函数,索引分别是0,1,2。
m_pListCtrl->InsertItem(0,"第一行");
行索引从0开始,InsertColumn函数将在列表中建立一个行,如果数据有三行,就调用三次此函数,索引分别是0,1,2。
这里我们的初始化代码如下:
m_ListControl.InsertColumn(0, _T("姓名"), LVCFMT_LEFT, 100); m_ListControl.InsertColumn(1, _T("电话号码"), LVCFMT_LEFT, 100); m_ListControl.InsertColumn(2, _T("群组"), LVCFMT_LEFT, 100);
2).对于群组进行初始化
群组对应的控件变量名为m_ComboGroup,变量类型为CComboBox.
群组对应的值变量名为m_sGroup,变量类型为CString.
这里我们的初始化代码如下:
m_ComboGroup.AddString(_T("朋友")); m_ComboGroup.AddString(_T("同事")); m_ComboGroup.AddString(_T("家人")); m_ComboGroup.AddString(_T("同学")); m_ComboGroup.AddString(_T("网友")); m_sGroup = _T("朋友");
_T宏可以把一个引号引起来的字符串,根据你的环境设置,使得编译器会根据编译目标环境选择合适的(Unicode还是ANSI)字符处理方式
3).对于文件的初始化
FileName = "";
(涉及到文件,在Experiment3Dlg.h中添加访问对象为pubilc,类型为CString,名称为FileName的变量)
4).UpdateData(FALSE);
(UpdateData(TRUE)的作用是将文本框界面值跟新到控件变量;
UpdateData(FALSE)的作用是将控件变量的值更新到界面中)
-
为按钮载入、保存、退出、新建、更新、删除添加事件处理程序
按钮 类 消息类型 函数名 载入 CExperiment3Dlg BN_CLICKED OnBnClickedButtonload 保存 CExperiment3Dlg BN_CLICKED OnBnClickedButtonsave 退出 CExperiment3Dlg BN_CLICKED OnBnClickedButtonexit 新建 CExperiment3Dlg BN_CLICKED OnBnClickedButtonnew 更新 CExperiment3Dlg BN_CLICKED OnBnClickedButtonupdata 删除 CExperiment3Dlg BN_CLICKED OnBnClickedButtondelete 载入按钮的事件处理程序:
void CExperiment3Dlg::OnBnClickedButtonload() { // TODO: 在此添加控件通知处理程序代码 FileDialog.ShowOpen(); FileName = FileDialog.get_FileName(); try { book.LoadFile(FileName); RefreshData(false); } catch (exception& e) { MessageBox(CString(e.what()),CString("Warning!")); } }
为了方便刷新数据,创建一个RefreshData函数:
void CExperiment3Dlg::RefreshData(bool fromDlgToBook) { // TODO: 在此处添加实现代码. if (fromDlgToBook) { int Count = m_ListControl.GetItemCount(); //获取列表框的行数 CString sName, sNumber, sGroup; string name, number, group; if (Count > 0) { book.clear(); for (int index = 0; index < Count; index++) { sName = m_ListControl.GetItemText(index, 0); sNumber = m_ListControl.GetItemText(index, 1); sGroup = m_ListControl.GetItemText(index, 2); name = string(CW2A(sName.GetString())); number = string(CW2A(sNumber.GetString())); group = string(CW2A(sGroup.GetString())); book.AddContact(name, number, group); } } } else { int Count = book.getCount(); CString sName, sNumber, sGroup; string name, number, group; if (Count > 0) { m_ListControl.DeleteAllItems(); for (int index = 0; index < Count; index++) { book[index].getContact(name, number, group); sName = CString(name.c_str()); sNumber = CString(number.c_str()); sGroup = CString(group.c_str()); m_ListControl.InsertItem(index, sName); m_ListControl.SetItemText(index, 1, sNumber); m_ListControl.SetItemText(index, 2, sGroup); } } } }
如果传入值为True,就把列表框中的数据更新到我们的vector中,如果传入值为False,就把vector中的数据更新到列表框中。
我们定义的这个函数其实有点类似于MFC自带的UpdateData函数(之前在初始化的时候用过),只不过UpdateData函数实现的是对话框中的数据和控件变量数据之间的更新,而我们这里定义的RefreshData函数,实现的是控件变量和vector容器之间的更新。
Tip: CW2A 将宽字符集(Unicode)转化为多字符集(ASCII)
CA2W 将多字符集(ASCII)转化为宽字符集(Unicode)
为列表添加一个事件处理程序,消息类型为NM_CLICK.表示如果选中地址簿中的一行,可以将该行的数据更新到联系人中给用户看:
void CExperiment3Dlg::OnNMClickListcontrol(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR); // TODO: 在此添加控件通知处理程序代码 POSITION pos; pos = m_ListControl.GetFirstSelectedItemPosition(); int index = m_ListControl.GetNextSelectedItem(pos); if (index >= 0) { string name, number, group; book[index].getContact(name, number, group); m_sName = CString(name.c_str()); //m_sNumber m_sNumber = CString(number.c_str()); m_sGroup = CString(group.c_str()); UpdateData(FALSE); } *pResult = 0; }
保存按钮的事件处理程序:
void CExperiment3Dlg::OnBnClickedButtonsave() { // TODO: 在此添加控件通知处理程序代码 if (FileName.IsEmpty()) { FileDialog.ShowSave(); FileName = FileDialog.get_FileName(); } try { book.SaveFile(FileName); } catch (exception& e) { MessageBox(CString(e.what()), CString("Warning!")); } }
新建按钮的事件处理程序:
void CExperiment3Dlg::OnBnClickedButtonnew() { // TODO: 在此添加控件通知处理程序代码 UpdateData(TRUE); if (!m_sName.IsEmpty()) { int count = m_ListControl.GetItemCount(); m_ListControl.InsertItem(count, m_sName); m_ListControl.SetItemText(count, 1, m_sNumber); m_ListControl.SetItemText(count, 2, m_sGroup); string name(CW2A(m_sName.GetString())); string number(CW2A(m_sNumber.GetString())); string group(CW2A(m_sGroup.GetString())); book.AddContact(name, number, group); m_sName = ""; m_sNumber = ""; m_sGroup = "朋友"; UpdateData(FALSE); m_EditName.SetFocus(); } }
退出按钮的事件处理程序:
void CExperiment3Dlg::OnBnClickedButtonexit() { // TODO: 在此添加控件通知处理程序代码 OnOK(); }
更新按钮的事件处理程序:
void CExperiment3Dlg::OnBnClickedButtonupdate() { // TODO: 在此添加控件通知处理程序代码 UpdateData(TRUE); int position(m_ListControl.GetSelectionMark()); book[position].setContact(string(CW2A(m_sName.GetString())), string(CW2A(m_sNumber.GetString())), string(CW2A(m_sGroup.GetString()))); RefreshData(FALSE); }
删除按钮的事件处理程序:
void CExperiment3Dlg::OnBnClickedButtondelete() { // TODO: 在此添加控件通知处理程序代码 int position(m_ListControl.GetSelectionMark()); book.Delete(position); m_sName = ""; m_sNumber = ""; m_sGroup = "朋友"; UpdateData(FALSE); RefreshData(FALSE); }
排序按钮的事件处理程序:
void CExperiment3Dlg::OnBnClickedButtonsort() { book.sort(); RefreshData(FALSE); }
到这里,该MFC设计基本就结束了文章来源:https://www.toymoban.com/news/detail-447267.html
这本是一篇实验报告,至于为什么产生将它写好并发出来的想法,主要是明白了写实验报告的意义,刚开始跟着老师做完这个实验的时候,对里面的很多东西都是懵的,直到在写实验报告时,才慢慢理解写实验报告的目的其实就是内化这个项目里面所涉及到的知识的过程。也逐渐明白为什么会有那么多人在CSDN上发博客,一方面是内化自己所学的东西,一方面也是为了给那些正在学的人提供帮助。之前也有在学python的Django框架,但学的过程中很多地方不理解,就没有再学下去了。现在也知道以后该怎么去学习做一个项目,等有空一定要把Django拿下,也希望自己的这篇文章能给有需要的人提供力所能及的帮助。文章来源地址https://www.toymoban.com/news/detail-447267.html
到了这里,关于MFC 对话框与控件的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!