
意义
掌握MFC控件的基本使用,结合了面向对象和Window消息机制的知识。
选择做简单的成绩管理系统,该项目切合大学生实际情况。易于更好理解。
项目实现了成绩的增加、修改、删除、存储(文件读写操作)的功能。
创建项目
打开软件:VS2022;创建新项目MFC应用;选择基于对话框;有必要的话添加对话框标题(用户界面功能)
设置UI界面

1、工具控件:列表(List Control),编辑框(Edit Control),静态文本(Static Text),下拉框(Combo Box),按钮(Button);
2、列表控件属性: 视图为Report
3、下拉列表外观属性 : 类型为下拉列表;行为属性:数据是 男;女;
为UI控件添加变量(很详细,必须理解)
1、选中控件,右键鼠标,添加变量。

2、添加控制变量,类别、名称、访问权限。(完成所有控件的变量设置,都是重复操作)

3、类向导
界面全部控件添加变量的类型和名称 (选择对话框 右击选择类向导可查看全部控件变量)

可以看到5个按钮对应界面的增 删 改 确定 取消,7个编辑框对应界面相应的属性等。
代码部分
1、创建两个类,一个为Student,存储学生的个人信息;一个为Management,管理学生的个人信息。
2、Student类包含七个成员变量,分别为学号、姓名、性别、年龄、地址、数学成绩、C++成绩。
3、Student类成员函数包括对 七个属性的值的获取与设置。
4、Management类成员变量即Student类列表。
5、Management类有四个成员函数对Student类进行 增 删 改 清
//Student.h
#pragma once
#include <iostream>
using namespace std;
class Student
{
private:string id;string name;string sex;string age;string address;string math;string programing;
public:Student();Student(string sid, string sname, string ssex, string sage, string saddress, string smath, string sprograming);void setName(string sname);void setId(string sid);void setAge(string sage);void setSex(string ssex);void setAddress(string saddress);void setMath(string smath);void setPrograming(string sprograming);string getName();string getSex();string getAddress();string getId();string getAge();string getMath();string getPrograming();friend ostream& operator <<(ostream& os, Student& st);friend istream& operator >>(istream& is, Student& st);friend bool LessMath(const Student* st1, const Student* st2);friend bool LessOop(const Student* st1, const Student* st2);~Student();
};
//Student.cpp
#include "pch.h"
#include "Student.h"
#include <iostream>
#include <string>
using namespace std;Student::Student() {}
Student::Student(string sid, string sname, string ssex, string sage, string saddress, string smath, string sprograming)
{id = sid;name = sname;sex = ssex;age = sage;address = saddress;math = smath;programing = sprograming;}
void Student::setName(string sname)
{name = sname;
}
void Student::setId(string sid)
{id = sid;
}
void Student::setAge(string sage)
{age = sage;
}
void Student::setSex(string ssex)
{sex = ssex;
}
void Student::setAddress(string saddress)
{address = saddress;
}
void Student::setMath(string smath)
{math = smath;
}
void Student::setPrograming(string sprograming)
{programing = sprograming;
}
string Student::getName()
{return name;
}
string Student::getSex()
{return sex;
}
string Student::getAddress()
{return address;
}
string Student::getId()
{return id;
}
string Student::getAge()
{return age;
}
string Student::getMath()
{return math;
}
string Student::getPrograming()
{return programing;
}
ostream& operator<<(ostream& os, Student& st)
{os << st.id << '\t' << st.name << '\t';os << st.sex << '\t' << st.age << '\t';os << st.address << '\t' << st.math << '\t' << st.programing;return os;
}istream& operator>>(istream& is, Student& st)
{is >> st.id >> st.name >> st.sex >> st.age>> st.address >> st.math >> st.programing;return is;
}bool LessMath(const Student* st1, const Student* st2)
{return st1->math > st2->math;
}
bool LessOop(const Student* st1, const Student* st2)
{return st1->programing > st2->programing;
}
Student::~Student(void) {}
//Management.h
#pragma once
#include"Student.h"
#include <list>
#include <fstream>
#include <string>
using namespace std;
class Management
{
private:list<Student*>studentArray;
public:Management();~Management(void);//删除数据void Clear();//删除数据void Add(Student* pSt);//加入数据Student* Delete(string id);//删除指定数据void Modify(string sid, string sname, string ssex, string sage, string saddress, string smath, string sprograming);//修改指定数据list<Student*>* GetStudent();void SortByMath();void SortByOop();bool Save(const char* fileName);bool Open(const char* fileName);
};//Management management;
//Management* management = new Management();
//Management.cpp
#include "pch.h"
#include "Management.h"
#include "Student.h"
#include <fstream>
#include <iostream>
using namespace std;
Management::Management() {}
Management::~Management(void)//删除数据
{for (auto iter = studentArray.begin(); iter != studentArray.end(); iter++){delete* iter;}
}
void Management::Clear()//删除数据
{for (auto iter = studentArray.begin(); iter != studentArray.end(); iter++){delete* iter;}
}
void Management::Add(Student* pSt)//加入数据
{studentArray.push_back(pSt);
}
Student* Management::Delete(string id)//删除指定数据
{Student* pSt = nullptr;for (auto iter = studentArray.begin(); iter != studentArray.end(); iter++){if ((*iter)->getId() == id){pSt = *iter;break;}}if (pSt != nullptr) studentArray.remove(pSt);return pSt;
}
void Management::Modify(string sid, string sname, string ssex, string sage, string saddress, string smath, string sprograming)//修改指定数据
{Student* pSt = nullptr;for (auto iter = studentArray.begin(); iter != studentArray.end(); ++iter){if ((*iter)->getId() == sid){pSt = *iter;break;}}if (pSt != nullptr){pSt->setName(sname);pSt->setSex(ssex);pSt->setAge(sage);pSt->setAddress(saddress);if (atof(smath.c_str()) >= 0.0) pSt->setMath(smath);if (atof(sprograming.c_str()) >= 0.0) pSt->setPrograming(sprograming);}
}
list<Student*>* Management::GetStudent()
{return &studentArray;
}void Management::SortByMath()
{studentArray.sort(LessMath);
}
void Management::SortByOop()
{studentArray.sort(LessOop);
}
bool Management::Save(const char* fileName)
{ofstream file(fileName, ios::out); //创建文件写入流if (!file) return false; //创建文件失败返回file << studentArray.size() << '\n'; //写入学生个数写入学生信息 转行隔开for (auto iter = studentArray.begin(); iter != studentArray.end(); ++iter){file << (**iter) << '\n';}file.close();return true;//返回创建成功
}
bool Management::Open(const char* fileName)
{Clear(); //原列表内容清空ifstream file(fileName, ios::in); //创建文件读入流if (!file) return false; //读入失败返回int n = 0;file >> n; //接收文件学生人数//为每个学生创建存储空间 并更新原有列表内容for (int k = 0; k < n; ++k){Student* pSt = new Student();file >> *pSt;studentArray.push_back(pSt);}file.close();return true; //返回读入成功
}
对话框的初始化
1、查找对话框初始化代码位置 (选择DIg类 项目会创建AboutDIg App DIg三个类)

2、添加代码(具体代码(主要是对列表控件的初始化 包括表头 还有风格))
//1、为列表控件加入表头CString strHeader[] = { _T("学号"),_T("姓名"),_T("性别"),_T("年龄"),_T("地址"),_T("数学"),_T("C++") };int nWidth[] = { 80,80,60,60,80,80,80 };for (int i = 0; i < 7; i++)M_studentList.InsertColumn(i, strHeader[i], LVCFMT_LEFT, nWidth[i]);//2、设置列表空间显示风格 整行选中 显示网格M_studentList.SetExtendedStyle(M_studentList.GetExtendedStyle()| LVS_EX_FULLROWSELECT| LVS_EX_GRIDLINES);
3、运行结果

完成到这里,很不错啦! 有一些成就感,我们往下继续
按钮事件编写(鼠标双击找到编写地方)
//增加按钮
void Cmfc08Dlg::OnBnClickedButton1()
{// TODO: 在此添加控件通知处理程序代码//0、将编辑框内容同步到变量UpdateData(TRUE);//1、往列表最后一行添加数据 count是用来记录学生个数的变量int newindex=M_studentList.InsertItem(M_studentList.GetItemCount(),M_id);M_studentList.SetItemText(newindex, 1, M_name);M_studentList.SetItemText(newindex, 2, M_sex);M_studentList.SetItemText(newindex, 3, M_age);M_studentList.SetItemText(newindex, 4, M_address);M_studentList.SetItemText(newindex, 5, M_math);M_studentList.SetItemText(newindex, 6, M_programing);//2、将编辑框的内容从CString转stringstring ID = CW2A(M_id.GetString());string NAME = CW2A(M_name.GetString());string SEX = CW2A(M_sex.GetString());string AGE = CW2A(M_age.GetString());string ADDRESS = CW2A(M_address.GetString());string MATH = CW2A(M_math.GetString());string PROGRAMING = CW2A(M_programing.GetString());//3、往类添加数据Student* pSt=new Student;pSt->setId(ID);pSt->setName(NAME);pSt->setSex(SEX);pSt->setAge(AGE);pSt->setAddress(ADDRESS);pSt->setMath(MATH);pSt->setPrograming(PROGRAMING);management.Add(pSt);//4、返回成功页面MessageBox(TEXT("添加成功!"));}
//修改按钮
void Cmfc08Dlg::OnBnClickedButton2()
{// TODO: 在此添加控件通知处理程序代码//0、将编辑框内容同步到变量UpdateData(TRUE);//1、获取列表选定索引int nIndex = M_studentList.GetSelectionMark();//2、更改列表内容M_studentList.SetItemText(nIndex, 0, M_id);M_studentList.SetItemText(nIndex, 1, M_name);M_studentList.SetItemText(nIndex, 2, M_sex);M_studentList.SetItemText(nIndex, 3, M_age);M_studentList.SetItemText(nIndex, 4, M_address);M_studentList.SetItemText(nIndex, 5, M_math);M_studentList.SetItemText(nIndex, 6, M_programing);//3、更改类内容string ID = CW2A(M_id.GetString());string NAME = CW2A(M_name.GetString());string SEX = CW2A(M_sex.GetString());string AGE = CW2A(M_age.GetString());string ADDRESS = CW2A(M_address.GetString());string MATH = CW2A(M_math.GetString());string PROGRAMING = CW2A(M_programing.GetString());management.Modify(ID, NAME, SEX, AGE, ADDRESS, MATH, PROGRAMING);//4、返回成功页面MessageBox(TEXT("修改成功!"));}
//删除按钮
void Cmfc08Dlg::OnBnClickedButton3()
{// TODO: 在此添加控件通知处理程序代码//1、获取列表选定索引int nIndex = M_studentList.GetSelectionMark();//2、从列表中删除M_studentList.DeleteItem(nIndex);//3、从类中删除string ID = CW2A(M_id.GetString());management.Delete(ID);//4、返回成功页面MessageBox(TEXT("删除成功!"));}
//确定按钮
void Cmfc08Dlg::OnBnClickedButton4()
{// TODO: 在此添加控件通知处理程序代码CDialog::OnOK();
}
//取消按钮
void Cmfc08Dlg::OnBnClickedButton5()
{// TODO: 在此添加控件通知处理程序代码CDialog::OnCancel();
}
查找列表选中触发事件 (属性 -> 事件 -> NM_CLICK -> ADD)
//单击列表内容
void Cmfc08Dlg::OnNMClickList2(NMHDR* pNMHDR, LRESULT* pResult)
{LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);// TODO: 在此添加控件通知处理程序代码*pResult = 0;//1、获取列表选定索引int nIndex = M_studentList.GetSelectionMark();//2、获取索引指定内容CString ID = M_studentList.GetItemText(nIndex, 0);CString NAME = M_studentList.GetItemText(nIndex, 1);CString SEX = M_studentList.GetItemText(nIndex, 2);CString AGE = M_studentList.GetItemText(nIndex, 3);CString ADDRESS = M_studentList.GetItemText(nIndex, 4);CString MATH = M_studentList.GetItemText(nIndex, 5);CString PROGRAMING = M_studentList.GetItemText(nIndex, 6);//3、将内容赋值给变量M_id = ID;M_name = NAME;M_sex = SEX;M_age = AGE;M_address = ADDRESS;M_math = MATH;M_programing = PROGRAMING;//4、将变量内容显示到编辑框UpdateData(FALSE);
}
调试一下,查看运行结果!!!

数据的存储
1、数据的保存——Management类的成员函数
bool Management::Save(const char* fileName){//创建文件写入流ofstream file(fileName, ios::out);//创建文件失败返回if (!file) return false;//写入学生个数file << studentArray.size() << '\n';//写入学生信息 转行隔开for (auto iter = studentArray.begin(); iter != studentArray.end(); ++iter)file << (**iter) << '\n';//文件关闭file.close();//返回创建成功return true;
}
2、数据的重新加载——Management类的成员函数
bool Management::Open(const char* fileName){//原列表内容清空Clear();//创建文件读入流ifstream file(fileName, ios::in);//读入失败返回if (!file) return false;//接收文件学生人数int n = 0;file >> n;//为每个学生创建存储空间 并更新原有列表内容for (int k = 0; k < n; ++k){Student* pSt = new Student();file >> *pSt;studentArray.push_back(pSt);}//文件关闭file.close();//返回读入成功return true;
}
3、打开原有文件按钮
//打开原有文件按钮
void Cmfc08Dlg::OnBnClickedButton6()
{// TODO: 在此添加控件通知处理程序代码//1、打开文件 对学生列表进行更新management.Open("studentmark.txt");//2、将原来的列表内容进行清空M_studentList.DeleteAllItems();//3、获取类中的学生信息list<Student*> arr = *(management.GetStudent());//4、将学生列表内容展现在列表上int count = 0;CString student[7];for (auto iter = arr.begin(); iter != arr.end(); iter++) {//string->CStringstudent[0] = (*iter)->getId().c_str();student[1] = (*iter)->getName().c_str();student[2] = (*iter)->getSex().c_str();student[3] = (*iter)->getAge().c_str();student[4] = (*iter)->getAddress().c_str();student[5] = (*iter)->getMath().c_str();student[6] = (*iter)->getPrograming().c_str();for(int i=0;i<7;i++)if(i==0)M_studentList.InsertItem(count,student[0]);elseM_studentList.SetItemText(count, i, student[i]);count++;}//5、返回成功页面MessageBox(TEXT("加载成功!"));
}
4、保存按钮——在确定按钮上作修改
//确定按钮 也称保存按钮
void Cmfc08Dlg::OnBnClickedButton4()
{// TODO: 在此添加控件通知处理程序代码//1、保存信息management.Save("studentmark.txt");//2、返回成功页面MessageBox(TEXT("保存成功!"));//3、关闭窗口CDialog::OnOK();
}
5、运行结果
5.1 项目下有被创建的txt文件

5.2 打开原有文件,保存的学生信息会被加载

注意事项
理解三个东西:解决方案资源管理器、类视图和资源视图。
解决方案资源管理器(Solution Explorer):解决方案资源管理器是用于组织和管理项目文件和资源的窗口。它**显示了整个项目的目录结构,包括源代码文件、头文件、资源文件等。**您可以在解决方案资源管理器中添加、删除、重命名文件,创建文件夹,对文件进行管理,并且可以通过拖放等方式进行文件的操作。
类视图(Class View):类视图提供了一个查看和导航项目中所有类的层次结构的窗口。它以树状结构展示了项目中的类和类成员,并且可以展开和折叠各个类的成员列表。通过类视图,您**可以快速浏览项目中的类的层次关系,查看类的基类、派生类、成员函数和成员变量等信息。**同时,您还可以在类视图中直接定位到具体的类或成员,方便地进行导航和查找。
资源视图(Resource View):资源视图用于管理MFC应用程序中的资源,如对话框、菜单、图标等。它允许您按照资源的类型来组织和管理项目的资源文件。通过资源视图,您可以添加、删除、修改和查看应用程序的各种资源,还可以在对话框编辑器中对对话框进行可视化设计和布局。












