基于MFC的通讯录管理系统

Schoolleave

发布日期: 2018-11-01 22:10:13 浏览量: 2716
评分:
star star star star star star star star star_border star_border
*转载请注明来自write-bug.com

一、设计目标及系统功能

1.1 设计目标

现在,随着人际交往的频繁,电子信息技术的发展,通讯录程序已经很多见。这次课程设计,目标是做出一个通讯录管理系统,可以实现对多个联系人的各项信息(包括姓名、联系方式、学籍信息等)进行管理与储存。

这个通讯录系统采用VisualC++ 6.0以及MFC编程,形成一个可视化的管理界面。并能实现联系人的添加、编辑以及删除,对联系人的信息进行查找与替换,按分组进行管理数据,写入单文件与数据加密,并实现与其他常用格式之间的互换等功能。

1.2 文件管理功能

通讯录系统能够实现对文件的集成式管理。由于设计的需要,文件中需要储存通讯录数据标题信息、密码信息(为了数据库安全可是对数据库设计密码访问)、分组信息以及联系人信息。通过程序的新建功能,可以很容易地创建一个数据库。

新建的过程中,必须要指出数据库的标题(数据库名)以及数据库的储存位置,并且同时可以指定数据库的访问密码。数据库的文件格式是文本格式,但是本系统中将数据库的拓展名定义为.txl,以和其它文件类型区分。这样,通讯录的一个数据库就建立完成。用户在对数据库的实时操作过程中,能够随时保存联系人信息,备份数据库信息,在退出程序时应提示用户保存联系人信息。

1.3 查找与替换功能

通讯录管理系统能实现对数据库中所存储的联系人进行逐一检索,比对需要进行查找的信息,然后将查找的结果显示出来,或者对查找的结果进行值的替换。查找的时候可以指定查找的方向,即向前查找还是向后查找,找到符合条件的记录之后将其显示出来,下一次查找将在本次查找的基础上继续查找,直到找到数据库的开头(向前查找)或者末尾(向后查找)为止。查找应该支持一定程度的模糊查询。例如,能检索出所有姓王的联系人。

替换的功能应在查找的基础上实现对其中的某一个字段进行值替换。由于替换工作的需要,需要一次性检索出所有符合条件的联系人并将其列表显示。可以进行选择性替换,也可以一次性完成替换。

无论查找还是替换,其针对的属性应该是联系人的全体属性,即能对联系人的每一个信息进行检索和替换。

1.4 分组管理功能

当联系人多了,管理起来就会比较麻烦。为了解决这一问题,我在数据库管理系统引入了分组管理的功能。用户可以按照自己的喜好对联系人进行分组操作(比如分为亲人、朋友、同学等),然后将联系人与分组对应。分组的信息可以动态添加、删除和编辑,并且程序可以按照分组实现对联系人的筛选,以便于对联系人的快速定位。

1.5 对联系人的添加、编辑与删除功能

作为一个通讯录管理系统,对联系人进行添加、编辑和删除的功能是一个基本的功能。对联系人的添加没有上限,只要计算机的物理设备支持,联系人想添加多少就添加多少。对联系人还能进行实时修改与保存,并且能取消不当的修改操作。当然,也可以对联系人进行删除操作,删除之前系统会给出警告。删除是进行彻底的,即一个数据库里的所有联系人可以都被删除。

1.6 文件交互功能

有时候,用户为了不一个字一个字地输入联系人信息,而拥有一个Excel的数据表,程序应该能够支持对这张数据表的导入。同时,用户想把联系人信息统计成Excel数据表,程序应该也能将联系人信息导出到数据表中。

所以,通讯录系统应该能实现两个功能,导入和导出。

导出功能包括TXT格式导出(与记事本程序交互的文件格式)和CSV格式导出(与Excel程序交互的文件格式),并且导出的时候保证所有有效信息的导出,保证对应格式的文件的有效性。

导入功能包括TXT格式导入(与记事本程序交互的文件格式)和CSV格式导入(与Excel程序交互的文件格式),以TXT方式导入的时候,系统将执行按行人名方式导入,以CSV方式导入的时候,系统应提取列表头信息,并实现列表头与联系人属性之间的智能匹配,对联系组的智能添加等功能。

1.7 辅助功能

除了以上的基本功能之外,通讯录管理系统还能支持一定程度的辅助功能,以增强程序的可用性。

生日提示功能。根据用户输入的联系人的生日信息,与系统时间比对,一旦到了联系人的生日的时候,系统能够提示用户哪些联系人的生日到了。

按拼音首字母检索的功能。这个功能是大部分优秀的通讯录软件所具有的一个功能,把所有联系人的姓名按第一个字的首字母拼音排列。例如,通过检索W能够检索到所有姓王的联系人。

成员快速分组功能。能够实现联系人快速分组的功能,避免挨个输入的麻烦。

二、系统开发的思路及实现

2.1 系统执行流程

程序的执行流程如右图所示,先是对程序的预处理,然后初始化各个类的信息,加载窗体及控件资源并按照设计显示出来。完成后根据用户的需要,可以进行创建数据库或者打开数据库,读入数据库的信息,并初始化各参数列表,将数据显示到窗体中。然后,根据用户的需要,对通讯录里的联系人信息、联系分组信息以及通讯录头信息进行编辑。

对联系人信息可以进行添加、编辑、删除、查询以及替换操作,对联系分组信息可以进行添加、编辑以及删除操作。通讯录头信息可以进行编辑,也可以对通讯录数据库进行导入导出操作。

对数据库的操作结束之后,进行保存操作将对数据库的修改信息写入到文件当中,然后退出程序。由于一切修改操作都只是在内存中进行的,所以一旦对数据库操作不当,可以选择不保存数据以恢复数据。

2.2 系统各项类的定义与使用

通讯录管理系统为了方便各项数据的管理,建立了八个类。CBaseInfor(管理联系人基本信息)、CStudyInfor(管理联系人学籍信息)、CContactInfor(管理联系人的联系方式信息)、COtherInfor(管理联系人的其它信息)、CPerson(管理联系人信息,综合联系人的四个子信息类)、CPGroup(管理联系分组信息)、CNoneGroup(管理未分组的联系人信息)、CDatabase(综合管理所有信息,包括联系人与分组信息的收集,文件的读入和写出)。对于联系人,我定义了姓名(name)、出生日期(birthday)、籍贯(province)、性别(sex)、所属分组(team)、职务(position)、专业(major)、学校(school)、班级(Class)、院系(college)、年级(grade)、家庭电话(phone)、手机(mobi)、家庭住址(address)、邮编(postcode)、QQ(qq)、邮箱(email)、传真(fax)、个人主页(homepage)、备注(memo)这20个属性进行描述。类的UML图如下所示:

各个类之间有着不同的关系,CPerson类是从CBaseInfor类、CStudyInfor类、CContactInfor类和COtherInfor类以公有方式继承的。CNoneGroup类是从CPGroup类公有继承而得的,CDatabase类则又是CPerson类和CPGroup类的组合。类的继承图如下图所示:

2.3 添加、编辑以及删除功能的实现

由于一个数据库储存的分组个数个联系人个数的不可预知性,同时为了检索的方便性,对于管理联系人和分组信息,通讯录管理系统采用链表的方式进行管理。

对于联系人,系统采用双向链表的方式进行管理。程序在运行之前定义了一个CDatabase类型的全局变量nowData,程序运行期间的所有操作便针对这个变量进行。在数据库类(CDatabase)中,定义了一个联系人类型(CPerson)的指针变量phead,用来存储第一个联系人的首地址。而对于联系人类(CPerson),定义了一个指向下一个联系人的联系人类(CPerson)指针next和一个指向上一个联系人的联系人类(CPerson)指针prev。如果这些指针指向NULL,则说明下一个联系人或上一个联系人不存在,也即到了联系人链表的起始处或末尾处。

联系分组类(CPGroup)的管理与之类似,只是联系分组不涉及双向查询,所以在联系分组类(CPGroup)中没有定义指向上一个联系分组的指针变量。

对于添加和删除联系人或联系分组,通讯录管理系统中分别重载了运算符+=和-=。执行一次+=,就把运算符右边的联系人或联系分组插入到链表的末尾。同样的,-=用于把运算符右边的联系人或联系分组从链表中删除。在重载+=运算符的时候,同时需要把联系人类(CPerson)和联系分组类(CPGroup)的用于统计个数的静态变量自加1。对于CPerson类来说,还需要按照插入的顺序设置联系人的ID号,同时,把新插入的联系人类(CPerson)的next指针指向空,prev指针指向原链表的最后一个联系人。而原链表的最后一个联系人的next指针则要指向新插入的这个联系人。对于联系分组,则少了设置prev指针这一步。

在重载-=运算符的时候,成功删除之后一样要将两个类的用于统计个数的静态变量自减1。按照类的特征变量(CPerson类的特征变量是ID,CPGroup类的特征变量是name)沿着链表进行检索,搜到符合条件的记录之后(由于特征变量是唯一的,所以符合条件的记录最多只有一条),将这条记录的上一条记录的next指针指向这一条记录的下一条记录。对于联系人类(CPerson)而言,还需要将这一条记录的下一条记录的prev指针指向这一条记录的上一条记录。将这条记录从链表中脱离之后,再用delete运算符将其所占用的内存空间释放掉。主要代码见附录。

有了上面的算法之后,我们便可以实现对联系人的添加和删除了。对联系人添加的窗口如上图所示。系统通过调用这个窗口,获得一些联系人常用的信息(其中姓名是必须给出的,其它信息可以不填),动态建立一块内存存储这个联系人的信息,再通过代码nowData+=*p;实现将这个联系人的信息插入链表的最后。

同理,插入联系分组的过程也是如此。用户通过菜单命令或快捷按钮调出新建联系组的对话框。由于联系分组的确立只需要联系分组的名称就行了,所以,只要在对话框中输入联系分组的名称,再通过调用nowData+=*g;即可向当前打开的数据库中分组链表中插入一个分组信息。

删除功能则更加简单,通过调用删除对话框,让用户选择并确认删除一个联系人或者分组之后,从链表中检索出这一记录,再调用nowData-=*p;就可以将对应的信息从链表里删除。

本通讯录管理系统中的编辑功能则主要是对应于当前记录的。对于一般的编辑功能,系统会在你修改确认之后搜索链表检索出要修改的联系人,然后将其对应的信息进行修改。如右图所示。这样修改需要调出修改对话框,还得找记录,不方便,所以系统还支持了当前记录修改的方式。在数据库管理类(CDatabase)中定义了一个指向联系人类(CPerson)的指针变量nowp,用于获得当前正在浏览或者编辑的联系人指针。如果链表中没有联系人,那么这个指针将指向NULL。

在主对话框中,有5个选项页分类地显示了当前浏览联系人的所有信息。当移动nowp指针的时候,这些信息也将及时更新。而在浏览信息的同时便可以对这些数据进行修改。为了防止误修改,每一页都设有保存修改和刷新按钮,用于保存或取消对该页内容进行的修改。这样,对联系人的编辑功能就变的十分快捷灵活。

2.4 数据的存储管理

为了提高程序的可用性,通讯录系统还设计了对文件操作的支持。为了减少对文件的频繁操作,系统在读入文件之后,一直对内存中的数据进行修改,执行保存指令的时候才将修改结果写回文件。这样,可以防止误操作的补课恢复性。

所有的联系人信息都将写入一个单一的文本文件中,为了数据的安全性,通讯录管理系统使用了自定义的文件格式(扩展名定义为*.txl)。文件中记录着数据库的头信息,分组信息以及联系人信息。文件的格式定义如下:

  1. 测试数据库 // 文件的开头第一行记录数据库的名字
  2. 111111 // 文件第二行记录数据库的访问密码,空行表示没设定密码
  3. [Group Information] // 分组信息开始的标记
  4. 同学 // 第一个分组的名字
  5. // 这里连续储存分组的名字,一个分组的名字一行
  6. 老师 // 第n个分组的名字
  7. [End Group] // 分组信息结束的标记
  8. 张三|1990-02-15|男|… // 这里开始储存联系人信息,各信息按序排列,用“|”分开
  9. // 每一行储存一个联系人信息,直到文件末尾
  10. 李华||男|… // 第n个联系人信息,没设置的信息留空

通讯录管理系统便依照这种格式,一次性读入所有联系人信息到内存中,以便以后对其进行各项操作。读入文件的功能在数据库管理类(CDatabase)的OpenFile函数中实现。实现的算法如下:

先利用fstream流对象以读的方式打开文件,采用getline方法按行读入。读入第一行,将其内容存储到数据库管理类(CDatabase)的title(标题)变量中。读入第二行,将其内容存储到数据库管理类(CDatabase)的password(密码)变量中。然后读入分组开始标记,以分组结束标记作为循环终止条件循环按行读入,每读一行向数据库变量(nowData)中添加分组信息。将所有分组信息读入完成之后,便按行读入联系人信息直到文件末尾。每当读入一行联系人信息的时候,再利用循环把这一行数据以“|”为分隔符进行分割转存,完成后将新的联系人信息添加到数据库变量(nowData)中。如此,所有信息便都读入内存了。

在读入文件之前,如果数据库设置了访问密码的话,应该先要求输入密码,确认了密码之后才能将数据读入。调用数据库管理类(CDatabase)的GetHeaderInfor函数(只读入前两行获得重要信息)获得数据库的名字和密码,如果密码不为空的话则弹出对话框要求输入密码,密码错误的话则取消打开操作。

相对于读入信息,保存信息的实现就变得简单多了,只要按照文件的格式将当前通讯录系统内存中的数据一次写入磁盘中即可。

2.5 查找与替换功能的实现

由于MFC提供的CString类的Find成员函数功能十分强大,查找的思路也变的十分简单。进行模糊查找,只要调用CString的变量s.Find(要查找的内容);就可以了。如果返回值大于等于零,则说明变量s中包含要查找的内容,否则说明不包含。

考虑到联系人可以被检索的属性比较多(20个),对每一个属性都添加一个检索的函数,并在检索的时候分支判断然后调用相应的检索函数需要的工作量比较大且可移植性差,所以,我在联系人类(CPerson)中添加了三个函数:GetMebValue、SetMebValue和CmpMebValue。这三个函数分别实现依据设置的属性名称获得属性值,设定属性值和查找属性值。GetMebValue中需要传入一个参数标识需要获得值的属性名称,返回值为获得的值。SetMebValue和CmpMebValue的第一个参数都是设置需要设置或者比对的属性名,SetMebValue的第二个参数传入需要设置的值,CmpMebValue的第二个参数传入需要查找的字符串,返回字符出现的位置数。

这三个函数的实现只是一个多分支的if语句,却明显减少了代码的编写工作量。

在实现查找的过程中,以nowp所指的联系人为查找起点,按照指定的查找方向利用next指针或prev指针对链表中的每一个结点进行比对,调用CmpMebValue(要查找的字段,要查找的内容)函数,通过返回值是否为不小于零的整数来判断是否符合查找条件。找到之后,设置当前数据库的nowp指针指向这条记录,调用刷新函数将查找结果显示到窗体上。而替换的过程只要在查找到之后调用SetMebValue来设置其对应的值。

2.6 分组管理的设计理念

本通讯录管理系统支持对联系人进行分组管理。每一个联系人都指定了一个team属性,用来设定该联系人从属于哪个组。对于一个确定的成员,分组的信息也是唯一确定的。当分组被设置成空字符串的时候,系统就把该联系人作为未分组的联系人处理。

分完组之后系统还能根据分组显示该组的联系人列表。根据列表,可以快速检索的联系人信息。对于每个人的分组归类,通过调用CPGroup::IsInThisTeam函数可以判断该成员是否从属于调用这个函数的组。

2.7 文件交互性设计

对于文本文档的导出功能,本系统采用一下格式。先输出一行标题,然后输出一条横线作为分隔线,然后一次输出每一个联系人的信息,每一行一个字段,输完一个联系人之后再后面追加一条分割线。

而对于文本文档的导入功能,本系统则采用行姓名导入方式。即把文本文档的每一行文本都当成一个联系人的姓名,一次添加到一个新的数据库当中。

至于对Excel程序的交互性,由于XLS数据表文件的高集成性,访问XLS文件的步骤十分复杂。所以,这里的和数据表进行导入导出选择的格式为CSV文件(逗点分隔文件)。该文件的格式十分简单,第一行为标题行,各字段名之间用逗号分隔。以后一行为一条记录,一条记录内每个字段之间的值也用逗号分隔。了解了这一特性之后,与Excel的交互便可以在CSV文件上展开。

首先,导出CSV文件的功能比较容易实现,先把标题栏按逗号分隔导出。然后把每一个联系人的数据按照逗号分隔的格式输出到文件即可。

导入CSV文件的时候,需要用户先对CSV文件中各字段与通讯录系统中使用的字段进行映射。通过两者之间是否有一者字符串包含另一者字符串来让系统实现初步地智能识别映射关系。通过CSV文件的文件名来智能识别导入数据库的名称。当一切参数都设定妥当之后。便依照设定的映射关系,逐行读入CSV文件中的记录,按逗号分隔信息,调用SetMebValue函数设置新建的联系人指定属性信息,加载完一行之后,将新建的联系人插入到链表中。如此,便完成了CSV文件的导入功能。

2.8 辅助功能的实现

按姓名首拼音进行检索。这项在知道某个联系人的姓名想要快速调出其对应信息的时候显得特别有用。首先,需要判定联系人的姓名是中文还是英文。判断姓名的第一个字符,如果介于A到Z之间或a到z之间,那么就认定联系人的姓名是英文的(对检索起影响的只有第一个字符)。如果联系人的姓名是英文的,则按英文的首字母进行检索。如果联系人的姓名是中文,则按姓名的拼音首字母进行检索。按英文的首字母检索实现起来比较容易,利用CString::GetAt()函数获取姓名的第一个字符,然后将其与检索的字符进行比对,如果一致就将其列出。而对于中文,由于中文字在电脑中的编码是按拼音排序的,故利用这一点,把中文汉字与临界汉字的编码进行比较,从而获得拼音首字母,再将拼音首字母与检索的字符进行比较。

生日提醒功能。由于在创建和修改联系人的时候,限制了日期输入的格式,所以,系统所存储的日期都是YYYY-MM-DD格式的(如1990-04-10)。所以,设计生日提醒的功能的思路如下:先建立CTime类获取系统时间,得到月份和日期信息格式转化为MM-DD型的字符串。然后对链表里的每一个成员进行检索,获取生日信息的后5个字符(就是去掉年份信息),如果和系统的时间一直,则显示该联系人的生日到了,继续下一个检索。这样,便实现了生日提醒功能。

联系人快捷分组功能。联系人信息在录入或者导入的过程中,往往是不带分组信息的,但是对每一个联系人都用编辑的方式进行分组的修改,其过程是十分繁琐的。所以,系统添加了联系人快捷分组的功能,利用两个列表框指定两个分组,用左移或者右移按钮动态修改联系人的分组信息,实现了鼠标一点,就能将联系人分组信息修改完成的功能。实现思想并不复杂,只是联系人链表逐一检索,将符合条件的联系人的分组信息设置成要移动到的分组名称。

2.9 容错处理

对于一些意外的事故以及一些非法的操作,程序做了一些容错处理。

首先,我在主对话框类中定义了一个EnableControls()函数,根据是否打开数据库而对界面上一些操作进行无效化处理。首先,在数据库管理类(CDatabase)中定义了一个共有的布尔型成员变量FileOpened,用来标记当前是否已经打开一个文件了。每当打开一个文件,该变量就会被设成true,关闭一个文件,该变量就会被设为false。当数据库为打开的时候,一些菜单(如新建联系人之类的)将变灰无法使用。界面上的控件也将无法使用。而文件打开后,部分功能对应激活,但是如果联系人链表是空的话,部分功能依旧无法使用(如删除联系人)。同理,分组链表是空的话预与之对应的功能(如删除分组)也无法使用。

其次,对数据的有效性进行判断。首先,保证记录的无重复性。每当新建一条记录的时候,系统会自动搜索整个链表以查找是否存在重复记录(只检验关键字,联系人类中为姓名,分组类中为名称),如果存在则提示无法新建。然后,对一些数据输入合法性进行检验。如生日分为年份、月份和日数三部分输入,对每一部分都进行检验,如年份为4位整数,月份为不超过12且大于0的整数等。

再者,由于程序是基于对话框构建的,所以在程序的任何一个位置按下回车或者Esc键是,主窗体都将退出并销毁,这并不是我们想看到的。为了解决这一问题,我重写了窗体类的消息处理函数如下,屏蔽了这两个键的作用:

  1. BOOL CContactDlg::PreTranslateMessage(MSG* pMsg)
  2. {
  3. if(pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_ESCAPE)
  4. return TRUE;
  5. if(pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_RETURN)
  6. return TRUE;
  7. else
  8. return CDialog::PreTranslateMessage(pMsg);
  9. }

三、开发中的难题与创新

3.1 多元化数据的管理

作为一个通讯录软件,需要管理的数据量是相当客观的。首先,作为联系人便有许许多多形形色色的联系方式以及个人信息需要分类归纳管理。其次,由于需要支持分组管理,对于联系人与分组之间的关系,联系人与分组的存储关系,这些都需要很好地组织起来。

为了解决这个问题,我将联系人的所有需要处理的信息分成四类进行管理。每个类分到的成员数大大减少,管理起来清晰方便。由于联系人总数和联系分组的总数的不可预知性,系统采用链表对其进行管理。其次,为了使联系人信息和分组信息管理方便,我向联系人中加了一个分组的属性,用这个属性来标记这个联系人属于哪个分组。另外将分组信息也构造成类,统一进行,管理,加上数据库标题和密码,组合成一个数据库管理类,用这一个类管理所有数据。

由于系统统一管理的数据类型并不单一,如何将这些信息存入文件又是一个问题。写入多个文件的话可移植性以及数据安全性会变差,写入单个文件又该怎样区分各个类型的数据呢?于是,我自己定义了一种文件格式,规定文件的头两行储存数据库头信息(标题和密码),然后利用分组信息标签对将分组信息与头信息和联系人信息分隔出来。联系人信息以一行一个联系人的方式存储,各信息之间用不常使用的字符“|”隔开。然后,再把这样格式的文件扩展名定义成.txl。这样,就基本解决这个问题了。

3.2 文件数据交互

无论是程序测试还是实际投入使用,作为通讯录程序,其所需要处理的数据量是十分大的。但是所有数据都手动录入显得比较麻烦。于是,很容易便想到与其它格式的数据进行数据交换。例如,拥有一个有着数千条通信记录的Excel数据表,能够一次性导入到数据库中就好了。再如,数据库中存了数条联系人信息,想导出数据进行加工处理。

但是XLS格式的文件是不容易操作的,这样为程序与Excel数据库交互造成障碍。但是注意到Excel支持对CSV格式的文件操作,而CSV文件格式是十分简单的,所以,程序除了与常规的TXT文件进行交互外,支持对CSV文件进行交互,从而提升了数据库系统的可用性。

3.3 特殊查询

由于通讯录管理系统需要处理的数据量可能非常大,这样一个强大的搜索功能便显得尤其重要。所以,检索必须是多样化的。

首先便是按值检索,也就是一般的查找功能。查找功能需要实现对联系人的任何字段都能进行查询,且支持包含查找,及可以查找某个字段中包含哪些文字。这一功能的实现,借助了CString类的Find()函数,切摈弃了对每一个字段都添加一个查找函数的繁杂方法,通过switch语句建立三个关键成员函数SetMebValue()、GetMebValue()以及CmpMebValue(),方便快捷地实现了查找。

其次便是按分组进行查询。用户可以通过选择不同的分组从而列出用户需要的联系人信息。按分组查询的实现方法比较简单,直接对联系人链表进行逐一检索,当检索的联系人的分组信息符合检索条件时将其显示出来。

最后便是按姓名首字母查询。这对于直接调出某一个人的信息提供了方便。对于英文名来说,这点实现起来并不困难,但是中文姓名又该怎样获取其拼音的首字母呢?通过查阅网上的大量资料,发现,中文汉字在电脑中编码是按照拼音的排序的,所以,要实现获取中文汉字的拼音首字母,只需将这个中文汉字的编码与26个临界汉字(拼音首字母为同一类的第一个字,如A的为啊)的编码进行比较,从而获得该汉字的拼音首字母,进而完成对汉字的首字母检索。

3.4 界面设计

对于程序界面的处理,系统采用了对话框式界面,集成图形菜单,用多选项卡的管理方式管理数据的各个信息。

在系统主对话框的左上角有一个快捷查找区域。这里的功能相当于编辑菜单下的查找菜单。在这里,可以快速地以当前联系人为起点,按照指定的查找方向对数据库中的所有联系人的指定字段进行不完全匹配查找。

在系统的左下角,有一个联系人分组树形图。该树形图很形象地反应了当前数据库的分组信息以及所有成员的从属组信息。该树形图还对数据库的分组信息以及各个分组拥有成员个数信息进行了初步的统计。

系统界面的右边则是一个有着5个选项卡的编辑界面。其中,常规选项卡中提供了按姓名首字母检索的功能,并列出了联系人的一些常用的信息。另外四个选项卡则是按分类将当前联系人的所有信息全都列了出来。每一个选项卡都可以直接对数据进行修改操作,也可通过单击刷新按钮取消修改,单击保存修改按钮保存所做的修改。

四、在收获中成长

4.1 事件驱动与消息循环

在查找关于MFC程序的资料的时候,也同时了解到了两个关于Windows应用程序开发相当重要的概念:事件驱动和消息循环。

事件驱动,简单的说就是程序相应用户或者系统所触发的事件吧。与我们之前编写的控制台应用程序不一样,面对图形界面以及一大堆控件,过程化驱动显得尤为苍白无力。而此时便体现出了事件驱动的优越性。程序可以等在那里接受用户操作的事件,并立即对之产生相应的回应,这样程序在可操作性和友好性上便大大的提高了。

而事件驱动的一个关键便是消息循环。应用程序执行后,便会建立起一个消息循环,捕获消息,处理消息,再将消息传给各个部件,各个部件则再对消息进行处理,选择需要相应的消息,并作出回应,这样便形成了事件驱动的机制了。

4.2 面向对象的设计思路

而MFC的编程,却将面向对象的设计思路体现得淋漓尽致。系统程序的每一个窗口都建立一个独立的类,从CDialog父类派生,继承出各个对话框,然后用户用过对对话框类的函数成员进行重载与补充,进而实现各种各样的功能,打造自己的个性化程序。

而这么做,很明确地体现了类的封装性和数据安全性,这对于建立一个安全稳固的系统是十分重要的。每个对话框都是一个类,每个对话框里处理的内容都是独立的,可以自己设置接口与外界进行交互,既保证了数据的安全,又不减程序的灵活性与可执行性。面向对象的设计思想,不仅提高了代码的利用效率,也增加了程序的稳定性和安全性。

上传的附件 cloud_download 基于MFC的通讯录管理系统.7z ( 4.20mb, 318次下载 )
error_outline 下载需要8点积分

发送私信

人生就像马拉松,获胜的关键不在于瞬间的爆发

8
文章数
20
评论数
最近文章
eject