C++ MFC 学习笔记+小型通讯录系统实现

MFC 最详细入门教程

[MFC常用函数总结](https://www.cnblogs.com/jiu0821/p/4606639.html)

[C++ & MFC]https://www.cnblogs.com/gaohongchen01/p/4176963.html

[MFC入门(一)]https://www.cnblogs.com/yangyuqing/p/10283641.html

[MFC快速入门]https://www.cnblogs.com/sea520/p/12582780.html

MFC教程(Visual C++ 6.0)|合集
https://blog.csdn.net/w_lin_jie/article/details/106601523?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168388113516782425197660%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=168388113516782425197660&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-2-106601523-null-null.142v87insert_down28v1,239v2insert_chatgpt&utm_term=vc%2B%2B6.0mfc&spm=1018.2226.3001.4187

MFC简介以及基础使用(小白级别入门讲解)

https://blog.csdn.net/qq_45549336/article/details/109008192?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168414038016800215071583%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=168414038016800215071583&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~hot_rank-1-109008192-null-null.142v87insert_down28v1,239v2insert_chatgpt&utm_term=mfc&spm=1018.2226.3001.4187

C++是一种静态数据类型检查的、支持多重编程范式的程序设计语言,支持过程化程序设计、数据抽象、面向对象程序设计、制作图标等泛型程序设计的多种程序设计风格。

MFC(Microsoft Foundation Classes),是一个微软公司提供的类库,以C++类的形式封装了Windows的API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量,同VCL类似,是一种应用程序框架。其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。此外MFC的部分类为MFC/ATL 通用,可以在Win32 应用程序中单独包含并使用这些类。

由于它的易用性,初学者常误认为VC++开发必须使用MFC,这种想法是错误的。作为Application Framework,MFC的使用只能提高某些情况下的开发效率,只起到辅助作用,而不能替代整个Win32 程序设计。

从C到C++

计算机诞生初期,人们要使用计算机必须用机器语言或汇编语言编写程序。

世界上第一种计算机高级语言诞生于1954年,它是FORTRAN语言。

BASIC语言是1964年在FORTRAN语言的基础上简化而成的。

C语言是1972年由美国贝尔实验室的D.M.Ritchie研制成功的。

C++是由AT&T Bell(贝尔)实验室的Bjarne Stroustrup博士及其同事于20世纪80年代初在C语言的基础上开发成功的,C++保留了C语言原有的所有优点,增加了面向对象的机制。

面向对象程序设计,是针对开发较大规模的程序而提出来的,目的是提高软件开发的效率。不要把面向对象和面向过程对立起来,面向对象和面向过程不是矛盾的,而是各有用途、互为补充的。学习C++,既要会利用C++进行面向过程的结构化程序设计,也要会利用C++进行面向对象的程序设计。

如果要用C++创建窗口,我们需要使用到系统API或者使用封装了这些API的一些库,前者如Win32程序设计,后者如MFC、wxWidgets。

其实我认为学习C++的初期当然是熟悉C++的语法,中期是学习STL等库、系统API以及熟悉C++的面向对象的思想和一般的设计方法;后期是伴随着你C++生涯的一生的,因为它没有终点的,这时候除了要继续加深对C++的理解之外,还需要去学习各种各样的基于C++的库,因为你需要在这些库的帮助下使用C++去实现更具体的东西,比如一些GUI库如MFC、QT、wxWidgets,一些游戏引擎如Ogre、Unreal、Bigworld等,一些网络库如ASIO、RakNet、ACE等。这些库大多有一个特点就是它们都是基于C++,封装了底层的API使得我们可以不必每次都去使用繁杂的API来实现我们想要的功能。当然,你也可以用C++去封装这些API,让自己成为一个库作者,方便他人。

C++发展历史

C++语言发展大概可以分为三个阶段:

第一阶段

从80年代到1995年。这一阶段C++语言基本上是传统类型上的面向对象语言,并且凭借着接近C语言的效率,在工业界使用的开发语言中占据了相当大份额;

第二阶段

从1995年到2000年,这一阶段由于标准模板库(STL)和后来的Boost等程序库的出现,泛型程序设计在C++中占据了越来越多的比重性。当然,同时由于Java、C#等语言的出现和硬件价格的大规模下降,C++受到了一定的冲击;

第三阶段

从2000年至今,由于以Loki、MPL等程序库为代表的产生式编程和模板元编程的出现,C++出现了发展历史上又一个新的高峰,这些新技术的出现以及和原有技术的融合,使C++已经成为当今主流程序设计语言中最复杂的一员。

MFC是什么

MFC,也称为Microsoft Foundation Class Library,是微软公司提供的一组用于编写Windows应用程序的C++类库。它是为了简化Windows应用程序开发而创建的,包括用户界面、窗口管理、消息处理、绘图设备、打印、文件系统、多媒体等方面的功能。MFC库由一组C++类和函数组成,使得开发者可以更加轻松地构建复杂的GUI界面、处理消息、调用Windows API函数等操作。MFC被广泛应用于Windows桌面应用程序的开发,例如Microsoft Office Suite等。

MFC还提供了丰富的控件和对话框,包括按钮、编辑框、列表框、组合框、树形视图、选项卡等常见组件,并支持自定义控件。通过继承MFC的框架类,开发者可以快速构建自己的应用程序界面。此外,MFC还提供了一些高级功能,如多线程支持、ATL COM技术、数据库访问等。目前,MFC虽然相对于现代的UI框架来说有些过时,但仍然是许多旧有Windows软件的主要代码库之一,对于一些需要兼容老系统或保持稳定性的项目来说,仍具有很高的价值。

MFC特点

编程语言函数本质上全部源于API,因此用它们开发出来的应用程序都能工作在Windows的消息机制和绘图里,遵守Windows作为一个操作系统的内部实现。

最后要明白MFC不只是一个功能单纯的界面开发系统,它提供的类绝大部分用来进行界面开发,关联一个窗口的动作,但它提供的类中有好多类不与一个窗口关联,即类的作用不是一个界面类,不实现对一个窗口对象的控制(如创建、销毁),而是一些在Windows(用MFC编写的程序绝大部分都在Windows中运行)中实现内部处理的类,如数据库的管理类等。学习中最应花费时间的是消息和设备环境,对C++和MFC。

MFC编程优势

C++语言应用极为广泛。尤其在底层编程和系统级编程上更是C++的传统优势应用。在数据库和多媒体方面,C++又以其卓越的稳定性而赢得了荣誉。

面对底层程序,它能很轻松的与Windows API或驱动程序结合,就是在自己的代码中直接使用API函数,而API和驱动程序的资料都是以C语言为基础的,这使得VC程序员能够更轻松的使用Windows API。这样造成了一个很有意思的现象,即入门时VC程序员要付出更多的努力来学习,但是一旦掌握后,开发其他领域的程序或使用第三方软件时,如工业控制类的程序,由于底层的程序都是用C语言编写,反倒是VC程序员能够更快的掌握该领域的编程技术。而很多其他的编程语言甚至找不到相关的资料。这就说明VC(MFC)实际上是一种入门困难,但是扩展学习却很轻松的语言框架。如果局限于某一领域的话VC毫无优势可言,但是如果开发一个新的领域的应用程序或者该程序涉及多个应用领域的话,可减少重复学习的频率和难度,VC(MFC)的优势会立刻显现出来。

MFC相关

MFC使用“Afx”作为所有的全局函数和全局变量的前缀。因为在MFC的早期开发阶段它叫“Application Framework Extensions”缩写为“AFX”。AFX提供了对Windows API的高度抽象,建立了全新的面向对象的AFX API,但它对于新手来说太复杂了,所以AFX小组不得不重新开始。后来他们创建了一组C++类,这就是MFC。MFC这个名字被采用得太晚了以至于没来得及修改这些引用。

在免费的Express版本的Visual Studio 2005/2008中没有包含MFC。

MFC作为一个强有力的竞争对手,为Borland的Turbo C++编译器设计OWL(Object Windows Library)在同一时间也发布了。但最后,Borland停止了对OWL的继续开发并且不久就从Microsoft那里购买了MFC头文件,动态链接库等的授权,微软没有提供完整的MFC的集成支持。之后Borland发布了VCL(Visual Component Library)来替换OWL框架。

MFC扩展DLL

每个DLL都有某种类型的接口:变量、指针、函数、客户程序访问的类。它们的作用是让客户程序使用DLL,MFC扩展DLL可以有C++的接口。导出的函数可以使用C++/MFC数据类型做参数或返回值,导出一个类时客户端能创建类对象或者派生这个类。同时,在DLL中也可以使用DLL和MFC。

Visual C++使用的MFC类库也是保存在一个DLL中,MFC扩展DLL动态连接到MFC代码库的DLL,客户程序也必须要动态连接到MFC代码库的DLL。(这里谈到的两个DLL,一个是我们自己编写的DLL,一个装MFC类库的DLL)现在MFC代码库的DLL也存在多个版本,客户程序和扩展DLL都必须使用相同版本的MFC代码DLL。所以为了让MFC扩展DLL能很好的工作,扩展DLL和客户程序都必须动态连接到MFC代码库DLL。而这个DLL必须在客户程序运行的计算机上。

C++ MFC 学习笔记+小型通讯录系统实现_第1张图片

MFC学习笔记

版权声明:本文为CSDN博主「鲨鱼小猫」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45549336/article/details/109008192

一、Windows消息机制

1.1窗口

一个Windows应用程序中至少有一个窗口,称为主窗口。我们在客户区进行图案的绘制。

1.2句柄

一个Windows应用程序是包含图标、光标等许多部件(资源),系统在为这些部件(资源)分配内存后会返回他们的标识号,也就是所谓的句柄。比如在Windows应用程序中,使用窗口句柄来标识每一个窗口。对窗口进行操作时候,首先就是得到这个窗口的标识。

1.3消息与消息队列

Windows是事件驱动方式的程序设计,当一个Windows应用程序开始执行的时候,系统会产生一个消息队列,用于保存这个窗口的消息。eg:当你自己在一个窗口中按下键盘时候(事件),系统会收集到这个按下键盘事情(事件),然后包装成消息,放到这个窗口的消息队列中(窗口过程)。因为队列的先进先出的特点,这时候窗口会一个一个的读取消息,然后进行相应的执行处理。

1.4WinMain函数

控制台DOS中的入口是mian函数,而WinMain函数就是Windows程序的入口函数。启动一个应用程序时候就开始先调用WinMain函数

1.5Windows编程模型

一个应用程序的功能是:创建一个窗口,然后响应键盘或者鼠标消息。

WinMain函数的定义

创建窗口
消息循环
窗口过程

MFC程序入口

//mfc头文件
#include

//1、应用程序类CWinApp,MyAPP派生类
class MyApp : public CWinApp{
public:
    //父类的虚函数,需要派生类进行重写
    //也是MFC函数的入口函数
    virtual BOOL InitInstance();
};

//2、框架类CFrameWnd,MyFrame派生类
class MyFrame : public CFrameWnd{
public:
    //构造函数
    MyFrame();
}

MFC.cpp

//对应类的头文件
#include "mfc.h"

//有且只有一个的全局应用程序类的对象
MyApp app;

//程序入口
BOOL MyApp::InitInstance(){
    //1、创建类框架
    MyFrame *frame = new MyFrame;
    //2、显示窗口
    frame -> ShowWindow(SW_SHOWNORMAL);
    //3、更新窗口
    frame -> UpdateWindow();
    //4、保存框架类对象指针
    m_pMainWnd = frame;
    return TRUE;
}

//重写构造函数
MyFrame::MyFrame(){
    //创建窗口
    Create(NULL,TEXT("mfc"));
}

2.3MFC的消息映射
消息映射就是将消息和成员函数相互关联的表。比如,Windows将一个鼠标左击消息放到一个框架窗口消息队列中,然后这个窗口取到这个消息时候,MFC将搜索该窗口的消息映射,如果存在一个处理鼠标左击消息(WM_LBUTTONDOWN)的处理程序,就调用。

下面是如何在一个类中编写一个消息映射

在操作的类中声明消息宏
通过放置标识消息的宏来执行消息映射,相应的类将对BEGIN_MESSAGE_MAP和END_MESSAGE_MAP的调用之间处理消息
mfc.h

class MyFrame : public CFrameWnd{
public:
    MyFrame();

    //声明消息宏
    DECLARE_MESSAGE_MAP()
}




//定义消息宏,在类中实现(派生类,父类)
BEGIN_MESSAGE_MAP(MyFrame,CFrameWnd)
    ON_WM_LBUTTONDOWN
END_MESSAGE_MAP()

//重写构造函数
MyFrame::MyFrame(){
    //创建窗口
    Create(NULL,TEXT("mfc"));
}

对应的处理函数分别在类中声明,类外定义

//框架类CFrameWnd,MyFrame派生类
class MyFrame : public CFrameWnd{
public:
    //构造函数
    MyFrame();
    //声明消息宏
    DECLARE_MESSAGE_MAP()
    //函数声明
    dfx_msg void OnLButtonDown(UINT,CPoint);
}

//定义消息宏,在类中实现(派生类,父类)
BEGIN_MESSAGE_MAP(MyFrame,CFrameWnd)
    ON_WM_LBUTTONDOWN
END_MESSAGE_MAP()

//重写构造函数
MyFrame::MyFrame(){
    //创建窗口
    Create(NULL,TEXT("mfc"));
}

//定义具体函数的实现
void OnLButtonDown(UINT,CPoint){
    .......
    .......
}

C++MFC是Microsoft Foundation Classes的缩写,是一种用于Windows操作系统的C++应用程序框架。它提供了一组类和函数,使得开发者可以使用面向对象的方法创建Windows GUI应用程序。

MFC主要包含以下几个部分:

  1. 应用程序类(CWinApp):处理应用程序的初始化、消息循环等操作。

  2. 窗口类(CWnd):封装了Windows窗口的基本行为,如位置、大小、可见性等。

  3. 对话框类(CDialog):用于创建对话框界面。

  4. 控件类:如按钮、文本框、列表框等,用于与用户交互。

  5. 消息映射机制:将Windows消息与类成员函数关联起来,实现事件响应功能。

MFC在Windows桌面应用程序开发中得到广泛应用,特别是当需要调用Win32 API时,MFC的封装能够简化代码,提高开发效率。但随着移动端和Web应用的兴起,MFC的应用范围逐渐收缩。

C++ MFC 学习笔记+小型通讯录系统实现_第2张图片
C++ MFC 学习笔记+小型通讯录系统实现_第3张图片
C++ MFC 学习笔记+小型通讯录系统实现_第4张图片

在这里插入图片描述
C++ MFC 学习笔记+小型通讯录系统实现_第5张图片

C++ MFC 学习笔记+小型通讯录系统实现_第6张图片
C++ MFC 学习笔记+小型通讯录系统实现_第7张图片
MFC(Microsoft Foundation Classes)是微软公司开发的一组类库,用于在Windows操作系统上开发C++应用程序。其中包括对话框类,可以基于对话框进行编程。

对话框是一种用于用户交互的窗口类型,通常包含各种控件,如按钮、文本框等,用户可以通过这些控件与程序交互。在MFC中,可以使用对话框类来创建和管理对话框。

要基于对话框进行编程,首先需要创建一个对话框资源,并将其添加到您的MFC项目中。然后,您需要创建一个对话框类,该类继承自CDialog或其派生类。在对话框类中,您可以处理对话框消息和控件事件,并执行所需的操作。

例如,您可以在对话框类中添加一个按钮,并为该按钮添加一个单击事件处理程序。在事件处理程序中,您可以编写代码以响应按钮单击事件,例如弹出一个消息框或执行一些其他操作。以下是一个简单的示例:

  1. 创建一个对话框资源。
  2. 创建一个对话框类,例如MyDialog,该类继承自CDialog类。
  3. 在对话框类头文件中添加一个成员函数,例如OnButtonClick。
  4. 在对话框类CPP文件中实现OnButtonClick函数,例如弹出一个消息框。
  5. 在对话框类中添加一个按钮控件,并将其与OnButtonClick事件处理程序关联。

这样,当用户单击该按钮时,系统将调用对话框类中的OnButtonClick函数,从而执行您所编写的代码。

C++ MFC 学习笔记+小型通讯录系统实现_第8张图片

C++MFC是Microsoft Foundation Classes的缩写,是一种用于Windows操作系统的C++应用程序框架。它提供了一组类和函数,使得开发者可以使用面向对象的方法创建Windows GUI应用程序。

MFC主要包含以下几个部分:

  1. 应用程序类(CWinApp):处理应用程序的初始化、消息循环等操作。

  2. 窗口类(CWnd):封装了Windows窗口的基本行为,如位置、大小、可见性等。

  3. 对话框类(CDialog):用于创建对话框界面。

  4. 控件类:如按钮、文本框、列表框等,用于与用户交互。

  5. 消息映射机制:将Windows消息与类成员函数关联起来,实现事件响应功能。

MFC在Windows桌面应用程序开发中得到广泛应用,特别是当需要调用Win32 API时,MFC的封装能够简化代码,提高开发效率。但随着移动端和Web应用的兴起,MFC的应用范围逐渐收缩。

利用MFC写一个通讯录系统

学习资源推荐

C++ MFC 学习笔记+小型通讯录系统实现_第9张图片

基于MFC的简易通讯录:

https://blog.csdn.net/weixin_43978807/article/details/90725232?spm=1001.2014.3001.5506

面向对象程序设计课程设计——MFC实现同学通讯录管理系统:

https://blog.csdn.net/weixin_44244154/article/details/103733614?spm=1001.2014.3001.5506

1.设计目的

同学通讯录管理程序是为了更好地管理学生信息而开发的数据管理软件。如今,同学与同学、老师与同学联系都是通过电话联系。但是,通常这些数据与其他人的信息混合在一起,同学信息并不方便被整理。
所以,同学通讯录管理程序为用户提供充足的信息和快捷的查询手段,实现学生基本信息的录入,删除,查询,修改,存到文件等几方面的功能,这样能对同学之间的信息进行更好的管理,使老师能更好地管理学生信息,对学生信息出现的变动也能及时进行修改。
与此同时,对所学面向对象的程序设计中所学知识加以利用和巩固:

1) 学习Visual C++的MFC开发程序的步骤。 
2) 综合运用所学的类、继承和多态的知识。
3) 进一步掌握程序的调试方法。
C++ MFC 学习笔记+小型通讯录系统实现_第10张图片

  1. 设计内容

1 利用MFC的向导,创建基于对话框的应用程序,添加按钮、编辑框等控件;
2 设计通讯录的数据结构(如:以数组或者动态链表)和相应的类;
3 完成对通讯录中记录的增加、修改、删除和显示。
4 将通讯录存入文件。能够打开并显示其中所存的同学信息,并可以进行后续的操作。
在设计同学通讯录管理程序时,我们小组采用对话框形式来进行处理,因为对话框窗口操作简单,更重要的是能更好的向使用者表达程序所要表达的信息。
在主界面进行设计时,我们小组分别设计了学号,姓名,系别,邮箱,电话等五个输入输出框,分别对学生的信息进行输入与输出。其次,设计了一个列表框使学生信息能更好的向用户展示,同时也更加方便了以后的操作。
最后,分别设计了添加记录、查询记录、删除记录、修改记录、保存信息、读取信息、清空所有数据和退出八个按钮,分别实现各自所对应的功能。

3.基本功能描述
3.1. 编辑框
**学号,姓名,系别,邮箱,电话静态文本后的输入输出框实现了对学生信息数据的输入输出。

3.2. 列表框
实现了对学生各个信息的显示,同时通过点击列表中的某一项来实现查看、修改等功能。

C++ MFC 学习笔记+小型通讯录系统实现_第11张图片

3.3. 按钮

  1. 添加记录:用户在输入输出框中输入信息,然后通过点击添加记录按钮,添加到列表框中。
  2. 查询记录:在除了系别这一信息外任意输入某一项或某几项信息后,点击查询记录按钮,程序将以姓名、电话、邮箱、学号的优先级递减顺序来查找符合条件的学生并将查询到的学生信息显示在输入输出框中。
  3. 删除记录:通过选中列表框中某一项,点击删除记录按钮删除所对应的学生数据,但不影响文件中的数据。
  4. 修改记录:通过选中列表框中某一项,在对话框中修改所对应的学生某项数据,然后点击修改记录按钮,修改列表框中所对应的数据信息,但不影响文件中的数据。
  5. 保存信息:将列表框中的信息全部保存到,目录下的“学生信息.txt”文件中,只有生成文件按钮才会通过程序影响文件中的内容。
  6. 读取信息:首先将列表中的已经显示的信息全部清空,再将储存在文件中的信息读取中列表中。
  7. 清空所有数据:删除全部学生信息,清空所有记录,同时也将文件中的信息清空。
  8. 退出:点击退出后弹出消息框“是否确认退出?”,若点击确认则退出程序,点击取消则返回当前程序**

4.设计思路
4.1. 窗口的设计
新建对话框程序,在对话框程序中添加各个控件,实现各个功能。

首先创建一般Student类,其中有共有CString公有数据成员name,number,phone,email,yuanxi,分别实现对学生邮箱,姓名,学号,电话,系别的存储。

class Student{
public:
CString name;
CString number;
CString phone;
CString email;
CString yuanxi;
};

再声明自定义类型Student的向量stu(初始容量为零)和用以确定列表控件行数的全局变量n(初始值为-1)。
为对话框创建CClassAddresslistDlg类,并设置各个变量与对话框各个窗口相关联。
通过编写点击各个按钮对应函数来完成各个按钮的功能:
添加记录:void CClassAddresslistDlg::OnBUTTONincrease();
查询记录:void CClassAddresslistDlg::OnBUTTONSearch();
删除记录:void CClassAddresslistDlg::OnBUTTONdelete();
修改记录:void CClassAddresslistDlg::OnBUTTONchange();
保存信息:void CClassAddresslistDlg::OnBUTTONpreserve();
读取信息:void CClassAddresslistDlg::OnBUTTONduqu();
清空所有数据:void CClassAddresslistDlg::OnBUTTONqingkong();
退出:void CClassAddresslistDlg::OnButtontuichu();
5.软件设计
5.1. 设计步骤

  1. 打开VC++6.0,新建MFC AppWizard[EXE]工程,在对话框中添加各个控件,完成程序窗口外观设计
  2. 在MFC ClassWizard中建立对话框类,并命名为CClassAddresslistDlg
  3. 在MFC ClassWizard中建立一般类,并命名为Student
  4. 在CStudentDlg类编写时,创建全局变量int n = -1(代表行数),通过n的值来方便为列表和按钮建立联系
  5. 在MFC ClassWizard为CStudentDlg中添加各个控件,并通过函数编写,实现具体的功能
  6. 调试与运行

5.2界面设计
界面由选项框区、通讯录信息区以及列表控件区三个区域组成。其中,通讯录信息区由有五个静态控件用来显示“学号”“姓名”“系别”“邮箱”“电话”字样,与各个静态控件相对应的是五个编辑框,实现了对学生信息的输入输出。列表框区用来显示当前已经存储的学生信息,选项框区有八个按钮,分别对应各自的功能。

6.关键功能的实现
*添加纪录:
首先用户需要在五个编辑框中分别输入信息。点击“添加纪录”按钮后,对应的函数首先声明将编辑框控件中的内容同步到变量中,接着声明了一个变量int flag = 1,用来选择性地执行接下来的if语句。接下来判断当前状态下用户是否输入了信息以及用户输入的信息是否已经在列表中,如果输入了合理的信息则执行接下来的if语句进行查找,反之则改变flag的值以避开用于加入新元素的if语句。随后将信息栏当中的关联变量置零,进行下一次操作时信息栏当中不再显示上次学生的信息。
保存信息:
将保存信息按钮与Dlg类相关联,用户点击保存信息后,利用IO流对数据进行输入和输入,采用ofstream新建一个对象out来打开一个文本文档,采取ios::trunc对文本文件中已有数据进行覆盖,并将变量中的信息利用out来储存到文本文件当中去,每输入一个学生的信息进行换行操作。由于CString是MFC中,而ofstream是ATL中,ofstream能写入的需要char ,因此需要进行类型的转化,来实现信息的保存。
读取信息:
将读取信息按钮与Dlg类相关联,用户点击读取信息后利用IO流对数据进行输入和输入,采用ifstream新建一个对象fin来打开一个文本文档,先利用list控件中的函数将列表清空,
同样需要进行类型的转化,再利用fin将文档中的内容输出到列表中,并与变量的数据相关联,将其同步到变量当中去,来实现信息的读取。
列表控件:
单击列表中的某一行,再左侧信息栏中对应出现相应的学生信息。将列表栏与Dlg类相关联,获得相应的学生信息后将其同步到信息栏的关联变量当中,实现列表栏与信息栏的同步。
C++ MFC 学习笔记+小型通讯录系统实现_第12张图片

7.核心代码实现

7.1列表控件与编辑框控件的关联:

void CClassAddresslistDlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult)   //使选中哪一行的信息编辑框出现哪一行的信息
{
	POSITION pos=m_list.GetFirstSelectedItemPosition(); //获得选中元素的位置
	n=m_list.GetNextSelectedItem(pos); //获得选中元素的索引
	CString x;
	x=m_list.GetItemText(n,0);
	m_Number=x;
	x=m_list.GetItemText(n,1);
	m_Name=x;
	x=m_list.GetItemText(n,2);
	m_Xibie=x;
	x=m_list.GetItemText(n,3);
	m_Email=x;
	x=m_list.GetItemText(n,4);
	m_Phone=x;
	UpdateData(false);
	*pResult = 0;	
}

7.2 添加纪录:

void CClassAddresslistDlg::OnBUTTONincrease() 
{
	int flag = 0;//以便于选择性执行if语句
	UpdateData(true);
	if(m_Name==""||m_Number==""||m_Xibie==""||
		m_Phone==""||m_Email=="")
	{
		flag = 1;
		MessageBox("输入信息不完善,请重新输入!");
	}
    if (flag==0)
	    for (int i = 0;i < stu.size();i++)
	{
		if ( stu[i].name == m_Name&&stu[i].phone == m_Phone&&stu[i].email == m_Email&&stu[i].number == m_Number&&stu[i].yuanxi == m_Xibie)		
		{   
			flag = 1;
			MessageBox("该学生信息已经添加!");
			break;
		}
	}
		if (flag==0)
	{
		int n=m_list.GetItemCount();
			m_list.InsertItem(n,"");
			m_list.SetItemText(n,0,m_Number);
			m_list.SetItemText(n,1,m_Name);
			m_list.SetItemText(n,2,m_Xibie);
			m_list.SetItemText(n,3,m_Email);
			m_list.SetItemText(n,4,m_Phone);
        stu.reserve(stu.size()+1);//增加容量以防止溢出
		Student s1;
		s1.name = m_Name;
		s1.number = m_Number;
		s1.yuanxi = m_Xibie;
		s1.email = m_Email;
		s1.phone = m_Phone;
        stu.push_back(s1);//往向量末尾加新信息
			MessageBox("添加成功!");
	m_Name="";
	m_Number="";
	m_Xibie="";
	m_Phone="";
	m_Email="";  //清空编辑框
	UpdateData(false);
	}	
}

7.3 保存信息:

void CClassAddresslistDlg::OnBUTTONpreserve() 
{
	ofstream fout("ZHM.txt",ios::trunc);

	int n=m_list.GetItemCount();
	for(int i=0;i<n;++i){
		string str = CString(stu[i].number);   //由于CString是MFC中,而ofstream是ATL中,ofstream能写入的需要char *
		string str1 = CString(stu[i].name); 
		string str2 = CString(stu[i].yuanxi); 
		string str3 = CString(stu[i].email); 
		string str4 = CString(stu[i].phone); 
		
		fout<<str.c_str()<<" "
			<<str1.c_str()<<" "
			<<str2.c_str()<<" "
			<<str3.c_str()<<" "
			<<str4.c_str()<<endl;
		if (fout.fail())  
			break;
	}
	fout.close();
	MessageBox("保存成功!");
}

7.4 读取信息:

void CClassAddresslistDlg::OnBUTTONduqu() 
{
	m_list.DeleteAllItems(); // 全部清空 
	ifstream fin("ZHM.txt",ios_base::in); 
	string a,b,c,d,e;
	fin>>a>>b>>c>>d>>e;
	for(int i=0;!fin.fail();++i){
		int n=m_list.GetItemCount();
		m_list.InsertItem(n,a.data());
		m_list.SetItemText(n,1,b.data());
		m_list.SetItemText(n,2,c.data());
		m_list.SetItemText(n,3,d.data());
		m_list.SetItemText(n,4,e.data());
		 MessageBox("读取成功!");
		Student s1;
		s1.number=a.data();
		s1.name=b.data();
		s1.yuanxi=c.data();
		s1.email=d.data();
		s1.phone=e.data(); 
		stu.reserve(stu.size()+1);//增加容量以防止溢出
	stu.push_back(s1);
	fin>>a>>b>>c>>d>>e;
	}
	fin.close();
}

C++ MFC 学习笔记+小型通讯录系统实现_第13张图片

其他

用C++的MFC编写一个通讯录系统,可以采用对话框为主界面,配合列表控件(CListCtrl)显示联系人信息。以下是一个简单的思路和基本的代码实现:

  1. 创建MFC项目,并选择基于对话框的应用程序。

  2. 在对话框中放置一个列表控件(ID为IDC_LIST_CONTACTS),并设置其属性以显示网格线和全行选中。在对话框类中添加成员变量CListCtrl m_listContacts;与该控件关联。

  3. 为了方便管理,我们可以创建一个Contact结构体,包含姓名、电话等成员。

  4. 在初始化对话框时,添加列表控件的列标题。

  5. 添加功能按钮,如添加、删除、修改联系人。

以下是一个简单代码示例:

// ContactManagerDlg.h
#pragma once
#include "afxcmn.h"

struct Contact {
    CString name;
    CString phone;
};

class CContactManagerDlg : public CDialogEx {
public:
    CContactManagerDlg(CWnd* pParent = NULL);

    enum { IDD = IDD_CONTACTMANAGER_DIALOG };

protected:
    virtual void DoDataExchange(CDataExchange* pDX);
    
protected:
    HICON m_hIcon;

    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()

public:
    CListCtrl m_listContacts;
    std::vector<Contact> m_contacts;

    afx_msg void OnBnClickedButtonAdd();
    afx_msg void OnBnClickedButtonDelete();
    afx_msg void OnBnClickedButtonEdit();
};
// ContactManagerDlg.cpp
#include "stdafx.h"
#include "ContactManager.h"
#include "ContactManagerDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CContactManagerDlg::CContactManagerDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_CONTACTMANAGER_DIALOG, pParent) {
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CContactManagerDlg::DoDataExchange(CDataExchange* pDX) {
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_LIST_CONTACTS, m_listContacts);
}

BEGIN_MESSAGE_MAP(CContactManagerDlg, CDialogEx)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BUTTON_ADD, &CContactManagerDlg::OnBnClickedButtonAdd)
    ON_BN_CLICKED(IDC_BUTTON_DELETE, &CContactManagerDlg::OnBnClickedButtonDelete)
    ON_BN_CLICKED(IDC_BUTTON_EDIT, &CContactManagerDlg::OnBnClickedButtonEdit)
END_MESSAGE_MAP()

BOOL CContactManagerDlg::OnInitDialog() {
    CDialogEx::OnInitDialog();

    SetIcon(m_hIcon, TRUE);
    SetIcon(m_hIcon, FALSE);

    m_listContacts.InsertColumn(0, _T("Name"), LVCFMT_LEFT, 100);
    m_listContacts.InsertColumn(1, _T("Phone"), LVCFMT_LEFT, 100);

    return TRUE;
}

void CContactManagerDlg::OnPaint() {
    if (IsIconic()) {
        CPaintDC dc(this);

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(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 CContactManagerDlg::OnQueryDragIcon() {
    return static_cast<HCURSOR>(m_hIcon);
}

void CContactManagerDlg::OnBnClickedButtonAdd() {
    // 实现添加联系人功能
}

void CContactManagerDlg::OnBnClickedButtonDelete() {
    // 实现删除选中联系人功能
}

void CContactManagerDlg::OnBnClickedButtonEdit() {
    // 实现编辑选中联系人功能
}

上述代码实现了一个基本的通讯录界面和对应的数据结构。需要注意这里并未实现具体的添加、删除和编辑功能,你可以根据需要进一步完善。此外,为了持久化通讯录数据,还可以考虑将联系人信息保存到文件或数据库中,并在启动时加载。

接下来,我们将实现添加、删除和编辑联系人的功能。首先需要创建一个新的对话框用于输入联系人信息(如姓名和电话),可以命名为CContactDlg

CContactDlg中,添加两个编辑框控件分别用于输入姓名和电话,为它们分别添加成员变量m_strNamem_strPhone

然后,在CContactManagerDlg类中实现添加、删除和编辑功能:

void CContactManagerDlg::OnBnClickedButtonAdd() {
    CContactDlg dlg;
    if (dlg.DoModal() == IDOK) {
        Contact newContact;
        newContact.name = dlg.m_strName;
        newContact.phone = dlg.m_strPhone;

        m_contacts.push_back(newContact);

        int nIndex = m_listContacts.GetItemCount();
        m_listContacts.InsertItem(nIndex, newContact.name);
        m_listContacts.SetItemText(nIndex, 1, newContact.phone);
    }
}

void CContactManagerDlg::OnBnClickedButtonDelete() {
    POSITION pos = m_listContacts.GetFirstSelectedItemPosition();
    if (pos) {
        int nSelected = m_listContacts.GetNextSelectedItem(pos);
        m_listContacts.DeleteItem(nSelected);
        m_contacts.erase(m_contacts.begin() + nSelected);
    }
}

void CContactManagerDlg::OnBnClickedButtonEdit() {
    POSITION pos = m_listContacts.GetFirstSelectedItemPosition();
    if (pos) {
        int nSelected = m_listContacts.GetNextSelectedItem(pos);

        CContactDlg dlg;
        dlg.m_strName = m_contacts[nSelected].name;
        dlg.m_strPhone = m_contacts[nSelected].phone;

        if (dlg.DoModal() == IDOK) {
            m_contacts[nSelected].name = dlg.m_strName;
            m_contacts[nSelected].phone = dlg.m_strPhone;

            m_listContacts.SetItemText(nSelected, 0, dlg.m_strName);
            m_listContacts.SetItemText(nSelected, 1, dlg.m_strPhone);
        }
    }
}

现在,你已经实现了一个基本的通讯录系统。接下来可以考虑优化和新增功能,例如:

  1. 将联系人信息保存到文件或数据库中,并在启动时加载。
  2. 添加搜索功能,允许用户搜索联系人。
  3. 支持按姓名、电话等字段排序联系人列表。
  4. 改进UI,使其更美观易用。

根据自己的需求和兴趣,你可以不断完善这个通讯录系统,使其更加强大和实用。

博客园

一、功能
构思确定通讯录的功能
1. 基本功能
- 添加联系人
- 删除联系人
- 修改联系人
- 显示联系人信息
2. 附加功能
- 查找联系人
- 读取保存联系人信息
3. 创意小功能
- 显示备注
- 电话号码必须为11- 双击报表视图中联系人即可修改联系人信息
- 查找联系人时报表视图只显示匹配的联系人信息
- 不允许添加重复联系人信息(一名联系人可以有多个电话)
- 未选中报表视图中联系人时修改联系人和删除联系人按钮不可用
- 查找联系人时根据关键字进行查找(即输入名字或电话的一部分或者仅选择群组都可以查找到匹配的联系人)

二、设计布局
1. 主对话框布局
在这里插入图片描述

左上角为List Control控件
所有虚线框都为Group Box控件
备注框为List Box控件
查找联系人中姓名框和电话框为Edit Control控件
查找联系人中群组框为Combo Box控件
查找联系人中姓名、电话和群组为Static Text控件
其余为Button控件
2. 添加联系人和修改联系人子对话框布局(两个对话框)
在这里插入图片描述

控件与主对话框的控件类型一样(自己判断)
通过点击主对话框中的添加联系人和修改联系人按钮分别弹出子对话框。
新建MFC应用程序的过程省略,类型选择基于对话框。(基本操作默认都会,不会的请自行百度)
子对话框可将自带的确认和取消按钮的Caption属性改成保存和取消即可。
在资源视图中的Dialog插入两个新的对话框作为上述两个子对话框。

三、设置类、成员变量、命令、及虚函数
通过类向导进行此步操作
1. 类
分别为三个对话框添加类,命名随意即可。MailListtDlg ContactAdding ContactModifying分别为本通讯录的主对话框类、添加联系人子对话框类、修改联系人子对话框类。(右键点击对话框找到添加类)

2. 成员变量
命名随意即可。

主对话框的成员变量
在这里插入图片描述第12项分别为群组框Combo Box的控件类别变量和值类别变量,第3456项分别为姓名框和电话框Edit Control的控件类别变量和值类别变量,第7项为备注框List Box的控件类别变量,第8项为报表视图List Control的控件类别变量。
子对话框的成员变量
在这里插入图片描述
第12项为群组框Combo Box的控件类别变量和值类别变量,第345项分别为姓名框、电话框、备注框Edit Control的值类别变量。
3. 命令

主对话框的命令
所有Button控件添加单击响应函数BN_CLICKED,List Control控件添加消息NM_CLICK DBLCLK。

子对话框的命令
所有Button控件添加单击响应函数BN_CLICKED。(若是将对话框自带的确认和取消按钮的Caption属性改成保存和取消则不用进行此项操作)

4. 虚函数
只需为两个子对话框各自添加一个初始化函数OnInitDialog。

四、代码编写
以下代码的类名请根据自己之前的命名进行修改,对象名的命名随意。不懂的函数自行百度(我都是百度看懂的)。代码的顺序按功能的构思思路进行安排。
1. 添加一个类存储联系人各项信息
新建一个头文件将此类写进去,在需要用到此类的cpp文件中include此头文件。

class MyClass {
public:
	//姓名,5个字内
	char Name[12];    
	
	//电话,11个数字                    
	char Phone[13];     
	
	//群组                     
	char Group[10];        
	   
	//群组索引(因为群组是ComboxBox控件,所以需要索引) 
	//初始化-1是为了当通讯录没有数据进行保存时不会错误将数据写入文件)                            
	int Group_Index = -1;      
	  
	//备注,50个字以内                          
	char Remark[104];                  
};
2、添加全局变量统计联系人人数和存储各个联系人

stdafx.h

//统计联系人人数
extern int N;
//存储各个联系人
extern MyClass new_people[100];
-----------------------------------------------------------------------
stdafx.cpp

int N = 0;
MyClass new_people[100];
3、主对话框的初始化函数
实现读取保存联系人信息功能。在头文件中进行read函数的声明,在实现文件中进行read函数的定义;read函数用于读入文件中已有的联系人信息,初始化函数用读入的联系人信息进行初始化主对话框,在报表视图中显示联系人信息。

read函数
MailListtDlg.h

void read();
-----------------------------------------------------------------------
MailListtDlg.cpp

void CMailListtDlg::Read(){
	CStdioFile file;
	CString str;
	file.Open("test.txt", CFile::modeRead);
	int now = 0;
	while (file.ReadString(str) != NULL){
		int i;
		if (now == 0) {
			N++;
			for (i = 0; i < str.GetLength(); i++) {
				new_people[N - 1].Name[i] = str[i];
			}
			new_people[N-1].Name[str.GetLength()] = '\0';
		}
		else if (now == 1) {
			for (i = 0; i < str.GetLength(); i++) {
				new_people[N-1].Phone[i] = str[i];
			}
			new_people[N-1].Phone[str.GetLength()] = '\0';
		}
		else if (now == 2) {
			strcpy_s(new_people[N-1].Group, str);
		}
		else if (now == 3) {
			new_people[N - 1].Group_Index = _ttoi(str);
		}
		else if (now == 4) {
			for (i = 0; i < str.GetLength(); i++) {
				new_people[N - 1].Remark[i] = str[i];
			}
			new_people[N-1].Remark[str.GetLength()] = '\0';
		}
		now++;
		now %= 5;
	}

}
初始化函数
BOOL CMailListtDlg::OnInitDialog(){
	CDialogEx::OnInitDialog();

	//初始化时读取文件内容,自定义的Read函数读取文件
	CMailListtDlg Read;
	Read.Read();   


	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标


	//设置报表视图的头标题        
	CRect rect;
	CListCtrl* pmyListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST4);
	LONG dwStyle = GetWindowLong(pmyListCtrl->m_hWnd, GWL_STYLE);
	SetWindowLong(pmyListCtrl->m_hWnd, GWL_STYLE, dwStyle | LVS_REPORT);
	LONG styles = pmyListCtrl->GetExtendedStyle();
	pmyListCtrl->SetExtendedStyle(styles | LVS_EX_FULLROWSELECT |LVS_EX_GRIDLINES | LVS_NOSCROLL);    
	pmyListCtrl->GetWindowRect(&rect);
	pmyListCtrl->InsertColumn(0, "姓名", LVCFMT_CENTER, rect.Width() / 3);
	pmyListCtrl->InsertColumn(1, "电话", LVCFMT_CENTER, rect.Width() / 3);
	pmyListCtrl->InsertColumn(2, "群组", LVCFMT_CENTER, rect.Width() / 3);


    //当导入了联系人信息且联系人信息非空时,报表视图按文本中联系人信息顺序显示                                                                    		    
	int nlist = m_ListCtrl.GetItemCount();
	if (new_people[0].Group_Index != -1) {
		CString str;
		for (int i = N - 1; i >= 0; i--) {
			str.Format("%s", new_people[i].Name);
			m_ListCtrl.InsertItem(nlist, str);
			str.Format("%s", new_people[i].Phone);
			m_ListCtrl.SetItemText(nlist, 1, str);
			str.Format("%s", new_people[i].Group);
			m_ListCtrl.SetItemText(nlist, 2, str);
		}
	}


    //Combo Box控件显示内容
	m_zhuGroup.AddString(_T(""));
	m_zhuGroup.AddString(_T("无"));
	m_zhuGroup.AddString(_T("家人"));                                               
	m_zhuGroup.AddString(_T("朋友"));
	m_zhuGroup.AddString(_T("同学"));
	m_zhuGroup.SetCurSel(0);


	//修改和删除联系人按钮灰显
	GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);                   
	GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE);


	return TRUE;
}
4. 单击“添加联系人”按钮的响应函数

void CMailListtDlg::OnBnClickedButton1()  {
	ContactAdding dlg;


	//弹出添加联系人子对话框,当子对话框通过保存键关闭时,进行if内的操作
	if (IDOK == dlg.DoModal()) {
		//添加联系人到报表视图 并存储到全局变量
		
		//获取当前报表视图的行数
		int i;
		CString str;
		int nHeadNum = m_ListCtrl.GetItemCount();
		
		//姓名
		str = dlg.m_Name2; 
		str.TrimLeft();
		str.TrimRight();
		//报表视图中插入姓名
		m_ListCtrl.InsertItem(nHeadNum, str);
		//将姓名存储到全局变量
		for (i = 0; i < str.GetLength(); i++){
			new_people[N].Name[i] = str[i];
		}
		new_people[N].Name[str.GetLength()] = '\0';
		
		//电话
		str = dlg.m_Phone2;
		//报表视图中插入电话
		m_ListCtrl.SetItemText(nHeadNum, 1, str);
		//将电话存储到全局变量
		for (i = 0; i < 11; i++){
			new_people[N].Phone[i] = str[i];
		}
		new_people[N].Phone[11] = '\0';
		
		//将群组索引存储到全局变量
		new_people[N].Group_Index = dlg.Group_Index;
		
		//将群组存储到全局变量
		m_zhuGroup.GetLBText(new_people[N].Group_Index + 1, new_people[N].Group);
		//报表视图插入群组
		m_ListCtrl.SetItemText(nHeadNum, 2, new_people[N].Group);
		
		//备注
		str = dlg.m_Variable2;
		str.TrimLeft();
		str.TrimRight();
		//将备注存储到全局变量
		for (i = 0; i < str.GetLength(); i++){
			new_people[N].Remark[i] = str[i];
		}
		new_people[N].Remark[str.GetLength()] = '\0';


		//联系人人数+1
		N++;
	}
}
进入添加联系人子对话框的初始化函数
BOOL ContactAdding::OnInitDialog()
{
	CDialogEx::OnInitDialog();


	//Combo Box控件显示“无”,并有另外三项选择
	m_ComboBox.AddString(_T("无"));
	m_ComboBox.AddString(_T("家人"));
	m_ComboBox.AddString(_T("朋友"));
	m_ComboBox.AddString(_T("同学"));
	m_ComboBox.SetCurSel(0);


	return TRUE;
}
单击添加联系人子对话框的保存按钮的响应函数
void ContactAdding::OnBnClickedOk()
{
	//将控件的值赋给成员变量
	UpdateData(TRUE);
	
	//判断电话号码是否为11位,若不为11位,报错
	if (m_Phone2.GetLength() != 11) {
		MessageBox("请输入11位的电话号码");
	}
	
	//若电话号码为11位
	else{
		//check函数判断是否存在重复电话号码,可以重复联系人姓名
		if (check() == 1) {
			m_Name2.TrimLeft();																	
			m_Name2.TrimRight();
			
			//名字不能为空
			if (m_Name2.IsEmpty()) {
				MessageBox("添加联系人信息不能为空");
			}
			
			//将群组ComboBox索引赋给该类的变量,将在关闭子对话框后使用
			else {
				Group_Index = m_ComboBox.GetCurSel();
				CDialog::OnOK();
			}
		}
		
		//check函数判断有重复电话号码
		else {
			MessageBox("请不要添加重复的联系人信息");
		}
	}
}

check函数判断是否存在重复联系人信息
在ContactAdding.h中声明check函数。联系人电话不可以重复,可以一人多号。
ContactAdding.h

int check();
------------------------------------------------------------------------------------------
ContactAdding.cpp

int ContactAdding::check() {
	char Phone[13];
	
	//类型转换
	for (int i = 0; i < m_Phone2.GetLength(); i++)
	{
		Phone[i] = m_Phone2[i];
	}
	Phone[m_Phone2.GetLength()] = '\0';

	//字符通过循环判断是否相同,不能用==判断
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < 11; j++) {
		
			//存在数字不相等即电话号码不相等,跳出该电话的循环
			if (Phone[j] != new_people[i].Phone[j]) 
				break;
				
		    //若循环进行到第十一数字,第十一个数字也相等,即该存在相同号码
			if (j == 10 && Phone[j] == new_people[i].Phone[j])	
				//打断循环并返回函数值			
				return 0;
		}
	}
	//若循环进行完全,即不存在相同号码
	return 1;
}

5. 单击“删除联系人”按钮的响应函数
删除联系人后相应会更新全局变量

void CMailListtDlg::OnBnClickedButton2()       
{
	//当在报表框中选择了一项
	while (m_ListCtrl.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED) != -1) {
	
		//获得选中项的索引
		int nItem;
		nItem = m_ListCtrl.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);
		
		//删除报表框中的选择的一行
		m_ListCtrl.DeleteItem(nItem);
		
		//更新全局变量信息
		for (int i = nItem; i < N; i++) {
			strcpy_s(new_people[i].Name, 11,new_people[i + 1].Name);
			strcpy_s(new_people[i].Phone, 12,  new_people[i + 1].Phone);
			strcpy_s(new_people[i].Group, 9, new_people[i + 1].Group);             
			strcpy_s(new_people[i].Remark, 102, new_people[i + 1].Remark);
			new_people[i].Group_Index = new_people[i + 1].Group_Index;
		}
		//联系人人数减一
		N--;		
		
		//删除、修改联系人按钮灰显
		GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
		GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE);
	}
	
	//清空备注框(因为选中报表框一项时备注框中会显示该联系人的相应备注)
	m_Variable.ResetContent();
}  

6、单击“报表视图”中一项的响应函数
备注框会显示选中联系人的备注信息。选中联系人后,修改联系人和删除联系人按钮可以使用。

void CMailListtDlg::OnClickList4(NMHDR *pNMHDR, LRESULT *pResult)   
{
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	DWORD dwPos = GetMessagePos();
	CPoint point(LOWORD(dwPos), HIWORD(dwPos));
	
    //查看点击位置
	m_ListCtrl.ScreenToClient(&point); 
	LVHITTESTINFO lvinfo;
	lvinfo.pt = point;
	lvinfo.flags = LVHT_ABOVE;
	int nItem = m_ListCtrl.SubItemHitTest(&lvinfo);
	
	//如果选中了联系人
	if (nItem != LB_ERR)                    
	{
		//先清空备注框
		m_Variable.ResetContent();
		
		//删除,修改按钮可按
		GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE);   
		GetDlgItem(IDC_BUTTON3)->EnableWindow(TRUE);   
		
		//备注框中显示相应联系人的备注
		m_Variable.AddString(new_people[lvinfo.iItem].Remark);
	}
	
	//点中了报表框中的空白处
	else {  
		//备注框清空
		m_Variable.ResetContent();    
		 
    	//删除,修改联系人按钮灰显                     
		GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);   
		GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE);  	
	}
	*pResult = 0;
}

9、单击“修改联系人”按钮的响应函数
在ContactModifying.h中声明两个int类型的变量,使修改联系人子对话框初始化时群组框能显示选中联系人的群组。

ContactModifying.h

int RecordList;
int RecordGroup_Index
------------------------------------------------------------------------------------------
MailListtDlg.cpp

void CMailListtDlg::OnBnClickedButton3() 
{
	ContactModifying dlg;


	//获得列表框选择的位置
	int nlist = m_ListCtrl.GetNextItem(-1, LVNI_SELECTED);              
	dlg.RecordList = nlist;
	dlg.RecordGroup_Index = new_people[nlist].Group_Index;


	//类型转换
	dlg.m_Name3.Format("%s", new_people[nlist].Name);
	dlg.m_Phone3.Format("%s", new_people[nlist].Phone);
	dlg.m_Group3.Format("%s", new_people[nlist].Group);               
	dlg.m_Group_Index3 = new_people[nlist].Group_Index;
	dlg.m_Variable3.Format("%s", new_people[nlist].Remark); 
	
	
	//弹出添加联系人子对话框,当子对话框通过保存键关闭时,进行if内的操作
	int nIdex = dlg.DoModal();
	if (nIdex == IDOK) {
		m_Variable.ResetContent();
		m_ListCtrl.DeleteItem(nlist);

		
		//全局变量信息更新+报表视图更新   
		CString str; int i; 
		
		//姓名                                                                                      		   
		str = dlg.m_Name3; 
		str.TrimLeft(); str.TrimRight();
		for (i = 0; i < str.GetLength(); i++) {
			new_people[nlist].Name[i] = str[i];
		}
		new_people[nlist].Name[str.GetLength()] = '\0';
		
		//更新报表视图
		m_ListCtrl.InsertItem(nlist, str);                                                   

		// 电话
		str = dlg.m_Phone3;
		str.TrimLeft(); str.TrimRight();
		for (i = 0; i < str.GetLength(); i++) {
			new_people[nlist].Phone[i] = str[i];
		}
		new_people[nlist].Phone[str.GetLength()] = '\0';
		
		//更新报表视图
		m_ListCtrl.SetItemText(nlist, 1, str);

		// 备注
		str = dlg.m_Variable3;
		str.TrimLeft(); str.TrimRight();
		for (i = 0; i < str.GetLength(); i++) {
			new_people[nlist].Remark[i] = str[i];
		}
		new_people[nlist].Remark[str.GetLength()] = '\0';

		// 群组
		new_people[nlist].Group_Index = dlg.m_Group_Index3;
		if (dlg.m_Group_Index3 == 0) 
			str = "无";
		else if (dlg.m_Group_Index3 == 1)
			str = "家人";
		else if (dlg.m_Group_Index3 == 2)
			str = "朋友";
		else if (dlg.m_Group_Index3 == 3) 
			str = "同学";
		for (i = 0; i < str.GetLength(); i++) {
			new_people[nlist].Group[i] = str[i];
		}
		new_people[nlist].Group[str.GetLength()] = '\0';
		
		//更新报表视图
		m_ListCtrl.SetItemText(nlist, 2, str);
		
		//删除、修改联系人按钮灰显
		GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
		GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE);
	}
}
进入修改联系人子对话框的初始化函数
群组框显示选中联系人的群组
BOOL ContactModifying::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	m_ComboBox3.AddString(_T("无"));
	m_ComboBox3.AddString(_T("家人"));
	m_ComboBox3.AddString(_T("朋友"));
	m_ComboBox3.AddString(_T("同学"));
	m_ComboBox3.SetCurSel(RecordGroup_Index);

	return TRUE; 
}
单击添加联系人子对话框的保存按钮的响应函数
void ContactModifying::OnBnClickedOk()
{
	//将控件的值赋给成员变量
	UpdateData(TRUE);
	
	//判断电话号码是否为11位
	if (m_Phone3.GetLength() != 11) {
		MessageBox("请输入11位的电话号码");
	}
	
	//若电话号码为11位
	else {
		//check函数判断重复信息(和添加联系人的check函数不一样)
		if (check() == 1) {
			m_Name3.TrimLeft();		
			m_Name3.TrimRight();
			//名字不能为空
			if (m_Name3.IsEmpty()) {
				MessageBox("添加联系人信息不能为空");
			}
			
			//将群组ComboBox索引赋给该类的变量,将在关闭子对话框后使用
			else {
				m_Group_Index3 = m_ComboBox3.GetCurSel();
				CDialog::OnOK();
			}
		}
		
		//check函数判断有重复电话号码
		else {
			MessageBox("请不要添加重复的联系人信息");
		}
	}
}
check函数判断是否存在重复联系人信息(注意和添加联系人的check函数的不同)
在ContactModifying.h中声明check函数。在修改联系人的过程中,存在只修改备注,不修改其他信息的情况,若使用添加联系人的check函数,会出现错误的报错。
ContactModifying.h

int check();
------------------------------------------------------------------------------------------
ContactModifying.cpp

int ContactModifying::check() {
	//类型转换
	
	//姓名
	char Name[12];
	for (int i = 0; i < m_Name3.GetLength(); i++)
	{
		Name[i] = m_Name3[i];
	}
	Name[m_Name3.GetLength()] = '\0';
	
	//电话
	char Phone[13];
	for (int i = 0; i < m_Phone3.GetLength(); i++)
	{
		Phone[i] = m_Phone3[i];
	}
	Phone[m_Phone3.GetLength()] = '\0';
	
	//当m=0时,即修改的电话和选中联系人的电话相同;当m=1时,则不相同
	int m = 0;
	for (int i = 0; i < 11; i++) {                                                  
		if (Phone[i] != new_people[RecordList].Phone[i]) {                      
			m = 1;
		}
	}
	
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < 11; j++) {
		
			//一个数字不相等即电话号码不相等,跳出该电话的循环
			if (Phone[j] != new_people[i].Phone[j]) 
				break;
				
			//若循环进行到第十一数字,第十一个数字也相等,即该存在相同号码 
			//m==1即相同号码不为选中联系人电话,判断为真实存在重复电话
			if (j == 10 && Phone[j] == new_people[i].Phone[j] && m == 1)
				return 0;
		}
	}
	//若循环进行完全,即不存在相同号码
	return 1;
}
8、双击“报表视图”中一项的响应函数
和单击“修改联系人”按钮的响应函数相同。

9、单击“查找”按钮的响应函数

实现根据关键字进行查找联系人的功能。(即输入名字或电话的一部分或者仅选择群组都可以查找到匹配联系人)
存在匹配联系人时报表视图只显示匹配联系人的信息。
void CMailListtDlg::OnClickedButton5()
{
	//将控件值传给成员变量
	UpdateData(TRUE);
	//声明定义一个MyClass对象存储信息
	MyClass Find;
	CString str; 
	
	//类型转换
	//姓名
	str = m_Name1;
	str.TrimLeft(); 
str.TrimRight();
	for (int i = 0; i < str.GetLength(); i++) 
		Find.Name[i] = str[i];
	Find.Name[str.GetLength()] = '\0';

	//电话
	str = m_Phone1;
	str.TrimLeft(); 
str.TrimRight();
	for (int i = 0; i < str.GetLength(); i++) 
		Find.Phone[i] = str[i];
	Find.Phone[str.GetLength()] = '\0';
	
	//索引
	//主对话框中的Combo Box索引数比其他子对话框的索引数多一个,因为主对话框中的ComboBox默认不显示,所以要-1
	Find.Group_Index = m_zhuGroup.GetCurSel() - 1;

	CString s1, s2;
	CString check;
	int Record[100];
	int record = 0;
	int que[100];
	for (int i = 0; i < 100; i++) {
		que[i] = i;
	}

	for (int i = 0; i < N; i++) {
		//类型转换
		s1.Format("%s", Find.Name);
		s2.Format("%s", Find.Phone); 

		//如果输入查找的群组和当前循环的群组不一样,则进行下一次循环
		//自己也没想懂逻辑
		if ((new_people[i].Group_Index == -1) || (Find.Group_Index != -1 && Find.Group_Index != new_people[i].Group_Index) || (Find.Group_Index == -1 && new_people[i].Group_Index != -1 && s1.IsEmpty() && s2.IsEmpty()))
			continue;

		//如果当前循环的姓名不存在输入查找的姓名或姓名的一部分,则进行下一次循环
		s1.Format("%s", Find.Name); 
		s2.Format("%s", new_people[i].Name);
		if (!s1.IsEmpty() && s2.Find(s1) == -1) 
 			continue;

		//如果当前循环的电话不存在输入查找的电话或电话的一部分,则进行下一次循环
		s1.Format("%s", Find.Phone); 
		s2.Format("%s", new_people[i].Phone);
		if (!s1.IsEmpty() && s2.Find(s1) == -1)  
			continue;

		Record[que[record]] = i;
		record ++;
	}
	
	//弹窗显示查找到多少名联系人
	check.Format("共查到%d条联系人", record);
	MessageBox(check);
	
	//如果找到匹配联系人,清空报表视图,只显示匹配联系人信息
	if (record > 0) {
		m_ListCtrl.DeleteAllItems();
		for (int i = 0; i < record; i++) {
			m_ListCtrl.InsertItem(i, new_people[Record[que[i]]].Name);
			m_ListCtrl.SetItemText(i, 1, new_people[Record[que[i]]].Phone);
			m_ListCtrl.SetItemText(i, 2, new_people[Record[que[i]]].Group);
		}
	}
}

10、单击“显示全部”按钮的响应函数

void CMailListtDlg::OnClickedButton6()
{
	//清空报表视图,因为查找后只显示匹配联系人信息
	m_ListCtrl.DeleteAllItems();


	//清空查找框中输入的信息
	m_Name11.SetWindowTextA("");
	m_Phone11.SetWindowTextA("");
	m_zhuGroup.SetCurSel(0);


	//报表视图显示所有联系人信息,提取全局变量
	for (int i = 0; i < N; i++) {
		m_ListCtrl.InsertItem(i, new_people[i].Name);
		m_ListCtrl.SetItemText(i, 1, new_people[i].Phone);
		m_ListCtrl.SetItemText(i, 2, new_people[i].Group);
	}
}

11、单击“保存”按钮的响应函数
将全局变量中的联系人信息写出文件保存,并用于下次读入。

void CMailListtDlg::OnBnClickedButton7()
{
	CStdioFile file;
	file.Open("test.txt", CFile::modeCreate | CFile::modeWrite);
	CString str;
	if (new_people[0].Group_Index != -1) {
		for (int i = 0; i < N; i++) {
		
			//姓名
			str.Format("%s\n", new_people[i].Name);
			file.WriteString(str);
			
			//电话
			str.Format("%s\n", new_people[i].Phone);
			file.WriteString(str);
			
			//群组
			str.Format("%s\n", new_people[i].Group);
			file.WriteString(str);
			
			//群组索引
			str.Format("%d\n", new_people[i].Group_Index);
			file.WriteString(str);
			
			//备注
			str.Format("%s\n", new_people[i].Remark);
			file.WriteString(str);
		}
	}
	MessageBox("保存成功");
	CDialogEx::OnCancel();
}

MFC是Microsoft Foundation Class的缩写,是一个用于Windows操作系统的C++类库,可以方便地开发GUI应用程序。下面是一些基本思路来设计一个通讯录系统:

  1. 界面设计:使用MFC框架创建一个对话框窗口,包含添加联系人、编辑联系人、删除联系人、搜索联系人和显示所有联系人等功能按钮。

  2. 数据存储:使用SQLite等关系型数据库,设计合适的表结构来存储联系人信息,如姓名、电话号码、邮箱、地址等。

  3. 添加联系人:当用户点击添加联系人按钮时,弹出一个新的对话框窗口,用户可以输入联系人的详细信息,然后将其存储到数据库中。

  4. 编辑联系人:当用户选择一个已经存在的联系人并点击编辑按钮时,弹出一个新的对话框窗口,在该窗口中显示选定联系人的详细信息,用户可以修改任何字段,保存修改后的信息到数据库中。

  5. 删除联系人:当用户选择一个已经存在的联系人并点击删除按钮时,弹出一个确认对话框窗口,以免误删,然后从数据库中删除该联系人。

  6. 搜索联系人:当用户在搜索文本框中输入关键字并点击搜索按钮时,根据输入的关键字查询数据库,并在一个列表视图控件中显示符合条件的联系人。

  7. 显示所有联系人:当用户点击显示所有联系人按钮时,从数据库中获取所有联系人信息,并在一个列表视图控件中显示。

  8. 数据校验:在添加或编辑联系人时,需要对输入的数据进行合法性校验,例如电话号码必须为数字、邮箱地址必须符合格式等。

  9. 错误处理:在程序运行过程中,可能会出现一些错误,如数据库连接失败、文件读写异常等,需要对这些错误进行捕获和处理,以便及时通知用户并解决问题。

  10. 界面美化:最后可以对界面进行美化,包括使用合适的字体、颜色和布局来提高用户体验。

在 MFC 应用程序中添加窗口控件的步骤如下:

  1. 打开资源视图,双击应用程序的 .rc 文件,打开资源编辑器。

  2. 在资源编辑器中选择一个对话框或者新建一个对话框。

  3. 在工具箱中选择想要添加的控件,比如按钮、编辑框、列表框等。

  4. 在对话框上使用鼠标拖动绘制出控件的大小和位置。

  5. 右键单击控件,选择属性,可以设置控件的属性,比如字体、颜色、默认文本等。

  6. 在代码中使用成员变量或者 GetDlgItem 函数获取控件的句柄,可以对控件进行操作,比如设置文本、字符格式、位置等。

  7. 如果需要响应控件的事件,比如按钮点击事件,可以通过添加响应函数的方式来实现。在类的消息映射表中添加 ON_CONTROL_RANGE 或者 ON_MESSAGE 宏,然后在类中实现响应函数即可。

以上是在 MFC 应用程序中添加窗口控件的基本步骤,需要根据实际情况进行具体实现。

C++ MFC 学习笔记+小型通讯录系统实现_第14张图片

你可能感兴趣的:(C++,mfc,c++,学习)