学院: 计算机科学与教育软件学院
专业/班级: 计算机科学与技术 173班
一、 实验目的
二、 实验内容
应用MFC应用程序实现学生信息管理系统
1、(1)设计一个学生类Student,包括数据成员:姓名、学号、二门课程(面向对象程序设计、高等数学)的成绩。
(2)创建一个管理学生的类Management,包括实现学生的数据的增加、删除、修改、按课程成绩排序、保存学生数据到文件按及加载文件中的数据等功能。
(3)创建一个基于对话框的MFC应用程序,程序窗口的标题上有你的姓名、学号和应用程序名称。使用(1)和(2)中的类,实现对学生信息和成绩的输入和管理。
(4)创建一个单文当的MFC应用程序,读取(3)中保存的文件的学生成绩,分别用直方图和折线图显示所有学生某课程的成绩分布图。
功能展示:打开应用,调出主界面
点击加载数据:可将之前保留的数据显示
添加学生:再点击加载数据
排序:(升序降序皆可)
点击列表头
按数学
按C++
其余功能不赘述。切入正题。
三、 实验步骤及程序代码
1、 打开vs2017->新建项目、创建MFC应用程序->命名,在这里我的是StuInfoManage(关乎对话框的ID名、类名、.cpp、.h名 每个人可按照自己的想法命名)->在应用程序类型下选择基于对话框,其他默认就好->点击完成。
2、 先搞好主界面布局:(其功能之后再实现)
打开资源视图(在视图菜单下,其他窗口/快捷键ctrl+shift+E)->一直展开到dilog文件,找到IDD_STUINFOMANAGE_DIALOG打开,进行控件布局(下图供参考)、取消按钮的caption改成退出管理界面,控件ID没作修改我是默认的。
关于一些控件的设置:
(1)改控件名字,对应控件右键属性,找i到caption,修改即可。
(2)LIst Control:右键属性view要改成report. 接着右键添加变量,类别控件, 变量类型ClistCtrl,名字m_nlist1.
(3)修改信息模块:
为每一个编辑框添加变量
姓名 :m_RName 值 CString
学号:m_RNumber 值 CString
地址:m_RAddress 值 CString
数学成绩:m_RMath 值 CString
c++成绩:m_CProgram 值 CString
年龄:m_RAge 值 CString
(4)Radio buttom:单选按钮 男 女
第一个单选按钮:属性中的:group为true tabstop为true auto为true
第二个单选按钮:对应为 false true true.
添加变量:只为第一个按钮添加m_RSex 值 Bool.
(默认选中第一个m_sSex=0,若选中第二个则m_sSex=1,分组中有多个单选按钮以此类推)
关于不同版本的编译器可能添加变量的界面会有所不同,并且有一些添加变量时没有自动绑定变量与控件。需要手动绑定。在cpp文件下找到函数
模仿着写。
(5)查找模块:
Combo box(下拉框):添加变量、类别控件、变量类型CComboBox、名称m_CCBox
Edit Control:添加变量:值、CString、名称:m_sSearch.
(6)统计人数模块:
Edit Control:添加变量:值、m_Population、CString.
3、 实现每一个按钮的功能:
在实现之前很重要的一点:在
打开解决方案资源管理器–头文件:
——StuInfoManage.h
#include "resource.h" // 主符号
//使用c++的语法
#include
#include //文件流
#include //string类字符串
#include //字符串流
#include //格式控制符
#include
using namespace std;
——StuInfoManageDlg.h
在里面添加:定义之后需要用到的一些函数变量。
//自定义的函数及变量
string name1, number1, sex1, age1, address1, math1, mfc1;
CString Oldnumber;
void SetList(); //将文件内容输出到列表
int item; //存储选中列表项标号
void Print(int x, string s[]);//自定义打印内容到列表项目函数
(1)添加学生信息:
首先添加多一个对话框(用于关联添加学生信息按钮)
在之前的资源视图->添加资源、选中dilog、点击新建(资源视图多一个IDD_DIALOG1)->布局成下图,其中将确定按钮和取消按钮的属性caption改成确认添加和返回管理界面
为这个对话框添加类(这里我设置的类名为ADD)
右键添加类(如图)
这里的编辑框和单选按钮的属性设置以及变量添加:
姓名:值 m_sName CString
学号:值 m_sNumber CString
性别:第一个按钮为caption属性为 男 group、Tabstop、Auto 均为true
另一个为女 group为false 其余为true
而且只为第一个单选按钮添加变量:值 m_sSex BOOL
通讯地址:值 m_sAddress CString
数学成绩:值 m_sMath CString
c++成绩:值 m_sCProgram CString
年龄: 值 m_sAge CString
确认添加按钮的响应事件:
双击该按钮:则会自动创建响应函数
先在响应函数上方写一个保存信息的函数Save():
//保存学生信息到文本 函数
void ADD::savefile(const char *filename)
{
ofstream outfile(filename, ios::app); //保存的时候用追加方式打开文本
if (!outfile) { MessageBox(CString("文件无法打开!!!")); return; }
else {
outfile << setiosflags(ios::left) << setw(20) << m_name << setiosflags(ios::left) << setw(20) << m_number
<< setiosflags(ios::left) << setw(20) << m_sex << setiosflags(ios::left) << setw(20) << m_address
<< setiosflags(ios::left) << setw(20) << m_math << setiosflags(ios::left) << setw(20) << m_mfc
<< setiosflags(ios::left) << setw(20) << m_age;
}
outfile.put('\n');
outfile.close();
}
接着在响应函数里面写入:
void ADD::OnBnClickedOk()
{
UpdateData(TRUE); //更新编辑框,单选框等信息获取信息到 绑定变量
if (m_sName != "") //判断
{
m_name = CStringA(m_sName); //将CString类数据类型转化为string字符串类,以便可以用流输入输出操作
}
if (m_sNumber != "")
{
m_number = CStringA(m_sNumber);
}
if (m_sAddress != "")
{
m_address = CStringA(m_sAddress);
}
if (m_sMath != "")
{
if (_ttoi(m_sMath) > 151 || _ttoi(m_sMath) < -1) { MessageBox(_T("该成绩爆表,请再确认一次,有效成绩(0 - 150)")); return; }
m_math = CStringA(m_sMath);
}
if (m_sCProgram != "")
{
if (_ttoi(m_sCProgram) > 151 || _ttoi(m_sCProgram) < -1) { MessageBox(_T("该成绩爆表,请再确认一次,有效成绩(0 - 150)")); return; }
m_mfc = CStringA(m_sCProgram);
}
if (m_sAge != "")
{if(_ttoi(m_sAge) > 201 || _ttoi(m_sAge) < -1) { MessageBox(_T("请输入年龄范围(0 - 200)岁")); return; }
m_age = CStringA(m_sAge);
}
bool flag = true; //判断录入循环的结束
string s1, s2, s3, s4, s5, s6, s7;//存文本读出的数据
ifstream infile(filename, ios::in); //以只读方式打开文本
switch (m_sSex)
{
case 0:m_sex = "男"; break;
case 1:m_sex = "女"; break;
}
if (m_name == ""|| m_number=="") { MessageBox(CString("注意,姓名或学号不能为空!!!")); return ; }
else {
do
{
infile >> s1 >> s2 >> s3 >> s4 >> s5 >> s6 >> s7;
if (m_number == s2) { MessageBox(CString("学号已被占用!!!")); m_sNumber = ""; return ; }
/* if ((m_name == s1) && (m_sex == s3) && (m_address == s4) && (m_math == s5) && (m_mfc == s6) && (m_age == s7))
{
MessageBox(CString("这个人已存在信息文本中!!!"));
flag = false;
return ;
}*/
if (!(infile >> s1 >> s2 >> s3 >> s4 >> s5 >> s6 >> s7))
{
savefile(filename);
infile.close();
MessageBox(CString("该学生信息保存成功"));
flag = false;
//添加完即刻清空编辑框
ADD();
m_sName = "";
m_sNumber = "";
m_sAge = "";
m_sAddress = "";
m_sCProgram = "";
m_sMath = "";
m_sSex = 0;
UpdateData(FALSE);
}
}while (flag);
}
// TODO: 在此添加控件通知处理程序代码
return ;
}
在此cpp源文件头部加上:存储学生信息文件的路径
static char *filename = ".\\StuInfo.dat";//存储数据的文本
添加完成后,返回第一个对话框(主界面)把“添加学生信息”按钮接通 :
双击按钮:
//打开添加信息框按钮
void CStuInfoManageDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
ADD dlg;//定义添加对话框类对象,文件头要加 ADD 的.h头文件
dlg.DoModal();//调出对话框
}
在该cpp源文件头部加上:
#include"ADD.h"
OK,完成第一个功能!!!
(2)List Control的加载按钮:
我们先把List Control的初始化界面搞好:
右键列表选择类向导 — 虚函数 — 找到OnInitDialog—添加函数—编写代码
//初始化对话框
BOOL CStuInfoManageDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
// 获取编程语言列表视图控件的位置和大小
CRect rect;
m_nlist1.GetClientRect(&rect);
// 为列表视图控件添加全行选中和栅格风格
m_nlist1.SetExtendedStyle(m_nlist1.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
//设置列表项头信息
CString s1[7] = { _T("姓名") ,_T("学号") ,_T("性别") ,_T("通信地址") ,_T("数学成绩") ,_T("c++成绩"),_T("年龄") };
for(int i=0;i<7;i++){ m_nlist1.InsertColumn(i, s1[i], LVCFMT_CENTER, rect.Width() / 7, i); }
//设置下拉框菜单信息
for(int i=0;i<7;i++){ m_CCBox.InsertString(i, s1[i]); }
m_CCBox.SetCurSel(0);
CString str = _T("1706100113 计科173 严晓缘 管理学生信息系统界面 本次用户: ");
str += theApp.m_susername;
SetWindowText(str);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
先在响应函数上方编写下列SetList()函数
//打印数据到列表
void CStuInfoManageDlg::SetList()
{
int count = m_nlist1.GetItemCount(); //获取列表总行数
for (int i = -1; i <= count; i++)//清除列表所有项
{
m_nlist1.DeleteItem(0);
}
ifstream infile(filename, ios::in);
if (!infile) { cout << "\n对不起!!!没有找到信息文件!!!\n"; }
bool flag = true;//用于判断文本是否为空
string record;
CString record1;
while (infile >> record)
{
int j = 0;
record1 = record.c_str();//string转CString
m_nlist1.InsertItem(j, record1);//设置列表每一行第一项内容
for (int i = 1; i < 7; i++) {
infile >> record;
record1 = record.c_str();
m_nlist1.SetItemText(j, i, record1);//设置列表每一行的后几个内容
}
flag = false;
j++;
}
if (flag) { MessageBox(CString("还未添加任何学生信息!!!")); }
infile.close();
}
然后在响应函数中调用SetList()函数
//刷新列表的按钮
void CStuInfoManageDlg::OnBnClickedButton4()
{
SetList();
// TODO: 在此添加控件通知处理程序代码
}
用于对某些重要操作的再次确认,防止误操作
如图示:
选择某个学生信息进行删除时
可选择取消或者再次确认。
即打开资源视图–dialog–右键添加资源–布局如下
原本的确认和取消按钮不必更改。
只需添加类:右键–添加类–类名就叫做“wornbox”。
(3)删除学生信息按钮:
设置List Control:
添加“选中列表中的某一行信息”事件(响应函数):右键属性–控件事件–找到NM_CLICK–添加。
//获取列表项某一行序号
void CStuInfoManageDlg::OnNMClickList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
// 选择语言的名称字符串
NMLISTVIEW *pNMListView = (NMLISTVIEW*)pNMHDR;
item = pNMListView->iItem;//获取列表项位置,此变量是之前定义的
}
双击删除学生信息按钮:
先在—StuInfoManageDlg.cpp文件头部加上
#include"wornbox.h"//添加警告对话框的头文件
static char *filename1 = ".\\transiti.dat";//临时存放数据的文本
仔细看,在这下面调用wornbox对话框了!!!
//删除信息按钮
void CStuInfoManageDlg::OnBnClickedButton3()
{
if (-1 != item) //说明选中列表项
{
wornbox worn;//声明对话框类的对象worn,用于调用它的成员函数
if (IDOK == worn.DoModal())//判断如果在警告对话框中选择确认则执行删除代码功能
{
ofstream outfile(filename1, ios::out);//临时文件
ifstream infile(filename, ios::in);
if (!infile) { MessageBox(CString("无法打开文件进行删除!!!")); return; }
//文本删除
string sign;
CString Name;
bool flag = true;
string name, number, sex, age, address, math, mfc, str;
Name = m_nlist1.GetItemText(item, 0);//获取列表项目选中行的第一项
sign = CStringA(Name);//转成string类存储
while (infile >> name >> number >> sex >> address >> math >> mfc >> age)
{
if (name != sign)
{
outfile << setiosflags(ios::left) << setw(20) << name << setiosflags(ios::left) << setw(20) << number
<< setiosflags(ios::left) << setw(20) << sex << setiosflags(ios::left) << setw(20) << address
<< setiosflags(ios::left) << setw(20) << math << setiosflags(ios::left) << setw(20) << mfc
<< setiosflags(ios::left) << setw(20) << age << endl;
}
else
{
if (-1 != item)
{
MessageBox(CString("成功删除该学生信息!!!"));
}
break;
}
}
while (getline(infile, str)) { outfile << str << endl; }// 将剩余学生信息存到临时文本
outfile.close();
infile.close();
//将临时文件的内容转到原文本
ofstream out(filename, ios::out);
ifstream in(filename1, ios::in);
if (!out || !in)
{
MessageBox(CString("在删除过程中,找不到文件!!!")); return;
}
while (getline(in, str)) { out << str << endl; }
out.close();
in.close();
m_nlist1.DeleteItem(item); //删除选中的列表项
item = -1; //在每一次删除之后让列表处于未选择状态
}
item = -1;
// TODO: 在此添加控件通知处理程序代码
}
else MessageBox(CString("未选择!!请在列表中选择要删除的学生信息项!!"));
}
(4)修改学生信息功能
实现方式是先把在列表框选中的信息放在编辑框内,然后进行修改。
把选中的信息放到相对应的编辑框:
找到列表项的响应事件:
右键列表框–属性–控件事件–
也就跳到这里
添加代码:
// 选择语言的名称字符串
NMLISTVIEW *pNMListView = (NMLISTVIEW*)pNMHDR;
item = pNMListView->iItem;//获取列表项位置
//把列表框选中信息放在修改编辑框
//左边变量就是对应的编辑框绑定的变量
m_RName = m_nlist1.GetItemText(item, 0);
Oldnumber=m_RNumber = m_nlist1.GetItemText(item, 1);
if ((m_nlist1.GetItemText(item, 2)) == _T("男"))
m_RSex = 0;
else m_RSex = 1;
m_RAddress = m_nlist1.GetItemText(item, 3);
m_RMath = m_nlist1.GetItemText(item, 4);
m_CProgram = m_nlist1.GetItemText(item, 5);
m_RAge = m_nlist1.GetItemText(item, 6);
UpdateData(FALSE);//要使用此函数才可以更新数据到编辑框
双击确认修改按钮:
//修改按钮
void CStuInfoManageDlg::OnBnClickedButton1()
{
wornbox worn;
//worn.DoModal();
if (IDOK == worn.DoModal())
{if(m_RName==""|| m_RNumber==""|| m_RAddress==""|| m_RMath==""|| m_CProgram==""|| m_RAge=="")
{
MessageBox(_T("请注意!!!不能将信息改成空")); return;
}
UpdateData(TRUE);//将修改后的编辑框内容传递给绑定的变量
bool f = true;//用于判断修改的学号是否已被用
if (Oldnumber != m_RNumber) {
ifstream infile(filename, ios::in);//读方式打开学生信息文本
if (!infile)
{
MessageBox(CString("在修改过程中,找不到文件!!!")); return;
}
while ((infile >> name1 >> number1 >> sex1 >> address1 >> math1 >> mfc1 >> age1) && f)
{
if (number1.c_str() == m_RNumber) { MessageBox(_T("该学号已被占用")); f = false; infile.close(); }
}
}
if (f) {
//将单选按钮选中的文字转成字符
CString s1;
if (m_RSex == 0) { s1 = "男"; }
else s1 = "女";
m_nlist1.DeleteItem(item);//清除原来留在列表框的一行
m_nlist1.InsertItem(item, m_RName);//设置列表每一行第一项内容
m_nlist1.SetItemText(item, 1, m_RNumber);//设置列表每一行的后几个内容
m_nlist1.SetItemText(item, 2, s1);
m_nlist1.SetItemText(item, 3, m_RAddress);
m_nlist1.SetItemText(item, 4, m_RMath);
m_nlist1.SetItemText(item, 5, m_CProgram);
m_nlist1.SetItemText(item, 6, m_RAge);
int count = m_nlist1.GetItemCount();//获取列表框行数
string s[7];
bool flag = false;
ofstream outfile(filename, ios::out);//写的方式打开临时文本
if (!outfile)
{
MessageBox(CString("在修改过程中,找不到文件!!!")); return;
}
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 7; j++)
{
s[i] = CStringA(m_nlist1.GetItemText(i, j));
outfile << setiosflags(ios::left) << setw(20) << s[i];
}
outfile.put('\n');
flag = true;
}
outfile.close();
if (flag)MessageBox(CString("修改学生信息完成!!!"));
m_RName = "";
m_RNumber = "";
m_RSex = 0;
m_RAddress = "";
m_RMath = "";
m_CProgram = "";
m_RAge = "";
UpdateData(FALSE);
}
// TODO: 在此添加控件通知处理程序代码
}
}
(5)表头排序
在—StuInfoManageDlg.cpp文件头部加上
DWORD dwSelColID = 0; //选择列表的列
BOOL bASC = FALSE; //是否升序
找到列表项的响应事件:
右键列表框–属性–控件事件–
添加代码:
//点击列表头项目响应函数
void CStuInfoManageDlg::OnLvnColumnclickList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
if (dwSelColID != pNMLV->iSubItem)//判断鼠标点击的是否和上一次是相同的一列
{
dwSelColID = pNMLV->iSubItem;//把新获取的某一列标号记录下来
bASC = bASC;//不升序
}
else
bASC = !bASC;
int count = m_nlist1.GetItemCount();
for (int i = 0; i < count; i++)
m_nlist1.SetItemData(i, i);
m_nlist1.SortItems(CompareFunc, (LPARAM)(&m_nlist1));
*pResult = 0;
}
然后在这个函数上方编写一个自定义函数:
//确认排序类型
static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
CListCtrl *pListCtrl = (CListCtrl *)lParamSort;//{这里面都是固定语法,适当了解
LVFINDINFO findInfo;
findInfo.flags = LVFI_PARAM;
findInfo.lParam = lParam1;
int iItem1 = pListCtrl->FindItem(&findInfo, -1);
findInfo.lParam = lParam2;
int iItem2 = pListCtrl->FindItem(&findInfo, -1);//这里面都是固定语法,适当了解}
CString strItem1 = pListCtrl->GetItemText(iItem1, dwSelColID); //需要研究
CString strItem2 = pListCtrl->GetItemText(iItem2, dwSelColID); //需要研究
char * str1 = (char *)strItem1.GetBuffer(strItem1.GetLength()); //需要研究
char * str2 = (char *)strItem2.GetBuffer(strItem1.GetLength()); //需要研究
if (dwSelColID == 1 || dwSelColID == 4 || dwSelColID == 5 || dwSelColID == 6)//int类型的比较
{
if (bASC)
return _ttoi(strItem1) < _ttoi(strItem2);//cstring转int
else
return _ttoi(strItem1) > _ttoi(strItem2);
}
if (dwSelColID == 0 || dwSelColID == 2 || dwSelColID == 3)//字符串CString比较
{
if (bASC)
return strcmp(str1, str2);
else
return strcmp(str2, str1);
}
return 0;
}
其中dwSelColID是所选择的列标号:
从左到右依次是0 1 2 3… 可以看出我这里的1,4,5,6列需要用int类型比较大小
0,2,3用字符比较大小
(6)查找学生
在—StuInfoManageDlg.cpp里面找到oninitDialog()函数
在里面添加代码:
//设置下拉框菜单信息
for(int i=0;i<7;i++){ m_CCBox.InsertString(i, s1[i]); }
m_CCBox.SetCurSel(0);
双击查找按钮
//查找按钮响应函数
void CStuInfoManageDlg::OnBnClickedButton2()
{
UpdateData(TRUE);//更新查找编辑框内容到绑定的变量
int nIndex = m_CCBox.GetCurSel();//获取下拉框选中内容的编号
//用于每一次显示列表框,清除上一次的保留
int count = m_nlist1.GetItemCount(); //获取列表行数
for (int i = -1; i <= count; i++)
{
m_nlist1.DeleteItem(0);
}
string searchStr = CStringA(m_sSearch);//将查找编辑框的内容存到 searchStr
string s[7];//用于文件内容的存储
bool flag = true;
int j = 0;
ifstream infile(filename, ios::in);//打开文件
if (!infile) { MessageBox(CString("对不起,无法打开文件 .\\StuInfo.txt")); return; }
while (infile >> s[0] >> s[1] >> s[2] >> s[3] >> s[4] >> s[5] >> s[6])
{
if(nIndex==0)
{ if (s[0] == searchStr) //匹配姓名
{
flag = false;
Print(j, s);
j++;
}
}
if (nIndex == 1)
{ if (s[1] == searchStr)//匹配学号
{
flag = false;
Print(j, s);
j++;
}
}
if (nIndex == 2)
{ if (s[2] == searchStr)//匹配性别
{
flag = false;
Print(j, s);
j++;
}
}
if (nIndex == 3)
{ if (s[3] == searchStr)//匹配通信地址
{
flag = false;
Print(j, s);
j++;
}
}
if (nIndex == 4)
{ if (s[4] == searchStr)//匹配数学成绩
{
flag = false;
Print(j, s);
j++;
}
}
if (nIndex == 5)
{ if (s[5] == searchStr)//匹配c++
{
flag = false;
Print(j, s);
j++;
}
}
if (nIndex == 6)
{ if (s[6] == searchStr)//匹配年龄
{
flag = false;
Print(j, s);
j++;
}
}
// TODO: 在此添加控件通知处理程序代码
}if (flag) { MessageBox(CString("没有与之匹配的学生信息!!!")); return; }
infile.close();//关闭文件
}
在此函数上面自己编写的一个将查找到的学生信息打印到列表
//用于查找到学生信息时打印到列表
void CStuInfoManageDlg::Print(int x,string s[])
{CString record1;
record1 = s[0].c_str();
m_nlist1.InsertItem(x, record1);
for (int i = 1; i < 7; i++)
{
record1 = s[i].c_str();
m_nlist1.SetItemText(x, i, record1);
}
}
还有其他功能(登陆框、成绩分布图)未完待续…
由于砖场繁忙,各位观看的大佬,小萌新们,告辞!!!
之后有空续写下一篇。
若各位小伙伴那里遇到有问题,欢迎联系QQ:1229686590
或者在评论区提出您的疑惑!