如题
(2)程序功能模块的设计:
1.学生管理系统的实现:
在我的程序里,MFC主对话框“学生管理系统”中拥有“保存”,“打开”,“添加”,“删除”,“按高数成绩排序”,“按C++成绩排序”,“修改”,“确定”,“反选”一共9个按钮,以及“学号”,“姓名”,“高数”,“C++”四个编辑框,还有一个list control列表用于显示数据。四个编辑框绑定了4个CString变量,利于直接获取数据,
在students managementDlg.cpp中拥有list control初始化的代码以及8个按钮分别对应实现的代码。在student.h头文件,里面用于存放一个“学生类”,在public中存放学生的姓名,学号,高数成绩,c++成绩,(分CString以及long long)两个类型存储,用一个convert成员函数实现从CString数据转变为long long存储以便实现排序功能。
在manageff.h头文件中,存放一个用于管理“学生类”的“管理类”,在private中存储len(管理学生的容器总大小),count(已存学生数量),public中实现构造函数(初始化),学生类指针(容器),获取容器大小的函数getcount,向容器中添加学生的函数add,指定位置删除容器中的学生函数del,根据高数成绩排序的函数math_sort,根据c++成绩排序的函数Cjj_sort以及判断容器中是否有相同学号的人的函数getsame(实现当添加时容器中已存在学号相同的学生则无法添加的功能)
在mangement.cpp中实现“学生类”以及“管理类”中的函数。
2.数据用直方图以及折线图显示的实现:
在MFC单文档中的View.h的类CView的public添加两个按钮CButton函数以及一个函数Open。在View.cpp中的OnDraw函数里实现的绘图,在类向导中添加一个OnCreate函数,并且实现按钮的显示。最后实现两个按钮的函数(打开“学生管理系统”中保存的save.txt,根据提取save.txt中的数据更改各个分段的高度以显示出直方图以及折现图)。
(3)带有详细注释的自己编写的关键源程序:
1.学生管理系统:
//将四个编辑框分别绑定四个CString变量:Id,name,math,Cjj
1.Student.h头文件:
#include
#define ll long long
using namespace std;
#pragma once
class student
{
public:
//除了name以外所有数据均存一份CString跟一份long long
ll Idq;
ll mathq;
ll Cjjq;
CString name;//姓名
CString Id;//学号
CString math;//高数成绩
CString Cjj;//C++成绩
void convert();//将存储的CString转换成long long
};
2.Manageff.h头文件:
#pragma once
#include "stdafx.h"
#include "Student.h"
class studentmanag
{
//学生类数组容器类
private:
int len;//容器总大小
int count;//容器已存的大小
public:
studentmanag();//构造函数
student * group;//学生数组容器
int getcount();//获取容器已存大小
void add(student x);//向容器添加一个学生
void del(int x);//从容器中选择删除一个学生
void math_sort();//按高数成绩排序数组
void Cjj_sort();//按C++成绩排序数组
bool getsame(student a);//判断容器中是否有学号相同的人
};
3.Management.cpp:
#include "stdafx.h"
#include "Student.h"
#include "manageff.h"
#include
using namespace std;
void student::convert()
{
//将CString转成long long型存储
Idq = _ttoi(Id);
mathq = _ttoi(math);
Cjjq = _ttoi(Cjj);
return;
}
studentmanag::studentmanag()
{
//初始化
group = new student[100];
len = 100;
count = 0;
}
int studentmanag::getcount()
{
//获取容器已存大小
return this->count;
}
void studentmanag::add(student x)
{
//容器添加操作
count++;
if (count >= len)//如果现有大小等于容器大小,则扩大容器
{
student *p = new student[len + 10];//开辟新容器
len += 10;
for (int i = 0; i < count - 1; i++)//将新容器复制旧容器
{
p[i] = group[i];
}
delete[]group;//删除旧容器的空间
group = p;//绑定新容器
}
group[count - 1] = x;
return;
}
void studentmanag::del(int x)
{
//容器删除操作
count--;
int times = count - x;
while (times--)
{
group[x] = group[x + 1];
x++;
}
return;
}
bool cmp1(student x, student y)
{
//用于排序高数成绩的cmp
if (x.mathq == y.mathq)
{
return x.Cjjq > y.Cjjq;
}
return x.mathq > y.mathq;
}
void studentmanag::math_sort()
{
//按高数成绩排序
sort(group, group + count, cmp1);
return;
}
bool cmp2(student x, student y)
{
//用于排序c++成绩的cmp
if (x.Cjjq == y.Cjjq)
{
return x.mathq > y.mathq;
}
return x.Cjjq > y.Cjjq;
}
void studentmanag::Cjj_sort()
{
//按C++成绩排序
sort(group, group + count, cmp2);
return;
}
bool studentmanag::getsame(student a)
{
//判断容器中是否存在学号相同的人
ll num = a.Idq;
bool flag = 0;
for (int i = 0; i < count; i++)
{
if (this->group[i].Idq == num)
{
flag = 1;
break;
}
}
return flag;
}
4.students managementDlg.cpp中关键源代码:
OnInitDialog函数中添加:
//这是listcontrol的初始化,初始化添加勾选框
m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES);
m_list.InsertColumn(0, _T("学号"),0,80);
m_list.InsertColumn(1, _T("姓名"),0, 80);
m_list.InsertColumn(2, _T("高数成绩"),0, 99);
m_list.InsertColumn(3, _T("C++成绩"),0, 97);
按钮实现:
void CstudentsmanageDlg::OnBnClickedButton3()
{
//添加按钮
UpdateData(TRUE);
//将编辑框中的数据写入学生类
student a;
a.Cjj = Cjj;
a.Id = Id;
a.math = math;
a.name = name;
a.convert();
if (stdmanag.getsame(a))
{
CString k = "学号重复了!";
MessageBox(k);
//弹出信息框k
}
else
{
stdmanag.add(a);//将该学生加入容器中
//将数据在列表中显示出来
int ncount = m_list.GetItemCount();
m_list.InsertItem(ncount, a.Id);
m_list.SetItemText(ncount, 1, a.name);
m_list.SetItemText(ncount, 2, a.math);
m_list.SetItemText(ncount, 3, a.Cjj);
}
}
void CstudentsmanageDlg::OnBnClickedButton2()
{
//删除按钮
for (int i = 0; i < m_list.GetItemCount(); i++)
{
//判断是否勾选
BOOL check = m_list.GetCheck(i);
if (check)
{
stdmanag.del(i);
//调用删除函数
m_list.DeleteItem(i);
//删除列表中该行数据
i--;
}
}
}
void CstudentsmanageDlg::OnBnClickedButton1()
{
//修改按钮
for (int i = 0; i < m_list.GetItemCount(); i++)
{
BOOL check = m_list.GetCheck(i);
if (check)
{
//如果勾选了该项
UpdateData(TRUE);
student a;
a.Cjj = Cjj;
a.Id = Id;
a.math = math;
a.name = name;
a.convert();
stdmanag.group[i] = a;
//根据编辑框中数据更新容器中学生数据
int ncount = m_list.GetItemCount();
m_list.SetItemText(i, 0, a.Id);
m_list.SetItemText(i, 1, a.name);
m_list.SetItemText(i, 2, a.math);
m_list.SetItemText(i, 3, a.Cjj);
//更新列表数据显示
}
}
}
void CstudentsmanageDlg::OnBnClickedButton4()
{
//按高数成绩排序按钮
int count = stdmanag.getcount();
stdmanag.math_sort();
//调用排序
m_list.DeleteAllItems();
//删除所有列表中所有数据
for (int i = 0; i < count; i++)
{
//容器中所有容器数据添加进列表
m_list.InsertItem(i, stdmanag.group[i].Id);
m_list.SetItemText(i, 1, stdmanag.group[i].name);
m_list.SetItemText(i, 2, stdmanag.group[i].math);
m_list.SetItemText(i, 3, stdmanag.group[i].Cjj);
}
}
void CstudentsmanageDlg::OnBnClickedButton5()
{
//按C++成绩排序按钮
int count = stdmanag.getcount();
stdmanag.Cjj_sort();
//调用排序
m_list.DeleteAllItems();
//删除所有列表中所有数据
for (int i = 0; i < count; i++)
{
//容器中所有容器数据添加进列表
m_list.InsertItem(i, stdmanag.group[i].Id);
m_list.SetItemText(i, 1, stdmanag.group[i].name);
m_list.SetItemText(i, 2, stdmanag.group[i].math);
m_list.SetItemText(i, 3, stdmanag.group[i].Cjj);
}
}
void CstudentsmanageDlg::OnBnClickedButton7()
{
//打开按钮
CFileDialog saveDlg(TRUE, ".txt", "save", OFN_OVERWRITEPROMPT, "文本文档(*.txt)|*.txt|所有文件(*.*)|*.*||", NULL);
//设置保存文件对话框格式
if (saveDlg.DoModal() == IDOK)
{
//如果按了保存
//获取文件路径,并且设置只读
CString path = saveDlg.GetPathName();
CStdioFile file(path, CFile::modeRead);
CString date;
student ui;
int i = 0, j = 0;
while (file.ReadString(date))//当还能读取到数据时
{
//将数据显示在列表中
if (i % 4 == 0)
{
m_list.InsertItem(j, date);
}
else
{
m_list.SetItemText(j, i % 4, date);
}
//将数据添加进容器
if (i % 4 == 0)
{
//第一行为学号
if (j != 0)
{
//除了第一个数据之外,当为4倍数时即说明ui已获取完一个学生数据
//然后添加进容器
ui.convert();
stdmanag.add(ui);
}
ui.Id = date;
}
else if (i % 4 == 1)
{
//第二行为姓名
ui.name = date;
}
else if (i % 4 == 2)
{
//第三行为高数成绩
ui.math = date;
}
else if (i % 4 == 3)
{
//第四行为C++成绩
ui.Cjj = date;
}
i++;
if (i % 4 == 0) j++;
//四个数据一换行
}
//将最后一个数据传进容器
ui.convert();
stdmanag.add(ui);
}
}
void CstudentsmanageDlg::OnBnClickedButton8()
{
//保存按钮
CFileDialog saveDlg(FALSE, ".txt", "save", OFN_OVERWRITEPROMPT, "文本文档(*.txt)|*.txt|所有文件(*.*)|*.*||", NULL);
//设置保存文件对话框格式
if (saveDlg.DoModal() == IDOK)
{
//如果按了保存
CString path = saveDlg.GetPathName();//获取文件路径
CString k = "文件已保存在路径";
CString k2;
k2.Format("%s%s", k, path);//k+k2
MessageBox(k2);
//弹出信息框k2
CStdioFile file(path,CFile::modeWrite|CFile::modeCreate);
//创建或者写入文件
//保存数据
CString cs, hh = "\n";
for (int i = 0; i < m_list.GetItemCount(); i++)
{
//i行
for (int j = 0; j < 4; j++)
{
//j列
cs = m_list.GetItemText(i, j);
file.WriteString(cs);
//写入一个数据
file.WriteString(hh);
//换行
}
}
file.Close();
//关闭文件
}
}
void CstudentsmanageDlg::OnBnClickedButton9()
{
//反选按钮
for (int i = 0; i < m_list.GetItemCount(); i++)
{
m_list.SetCheck(i, !m_list.GetCheck(i));//设置是否勾中
}
}
2.直方图以及折线图的显示:
在Doc.cpp中的OnNewDocument函数中添加以下代码(修改标题)
SetTitle(_T("直方图/折线图实现"));
1.在View.h中的Cview类的public添加以下代码:
afx_msg void OnClickButton1();
afx_msg void OnClickButton2();
//定义按钮1,2
CButton m_button;
CButton m_button1;
2.View.cpp中关键源代码:
int a = 0, b = 0, c = 0, d = 0, e = 0;
//矩阵高度
//在Ondraw函数中添加以下代码:
pDC->SetMapMode(MM_ISOTROPIC);
pDC->SetViewportOrg(200,450);//设置原点
pDC->MoveTo(100, 0);//从100,0画到1300,0
pDC->LineTo(1300, 0);
//设置画笔参数
CBrush brush;
//画笔颜色
brush.CreateHatchBrush(HS_BDIAGONAL, RGB(150, 100, 45));
pDC->SelectObject(brush);
int i = 1;
//绘制矩形,分别为四个点坐标
pDC->Rectangle(200, 0, 400, 50*a);
pDC->Rectangle(400, 0, 600, 50 * b);
pDC->Rectangle(600, 0, 800, 50 * c);
pDC->Rectangle(800, 0, 1000, 50 * d);
pDC->Rectangle(1000, 0, 1200, 50 * e);
//设置分段文本坐标
pDC->TextOut(250, 0, " <60");
pDC->TextOut(450, 0, "60-70");
pDC->TextOut(650, 0, "70-80");
pDC->TextOut(850, 0, "80-90");
pDC->TextOut(1050, 0, "90-100");
//设置文字高度(多少人)
CString y1,y2,y3,y4,y5;
y1.Format("%d", a);
y2.Format("%d", b);
y3.Format("%d", c);
y4.Format("%d", d);
y5.Format("%d", e);
//x轴从250-1050
pDC->MoveTo(250, 50 * a + 100);
pDC->LineTo(450, 50 * b + 100);
pDC->LineTo(650, 50 * c + 100);
pDC->LineTo(850, 50 * d + 100);
pDC->LineTo(1050, 50 * e + 100);
//设置文本位置
if(a!=0)
pDC->TextOut(250, 27 * a, y1 + "人");
if (b != 0)
pDC->TextOut(450, 27 * b, y2 + "人");
if (c != 0)
pDC->TextOut(650, 27 * c, y3 + "人");
if (d != 0)
pDC->TextOut(850, 27 * d, y4 + "人");
if (e != 0)
pDC->TextOut(1050, 27 * e, y5 + "人");
//在类向导中添加处理程序OnCreate
//在View.cpp中OnCreate函数添加以下代码:
m_button.Create("高等数学",//设置按钮1标题
WS_CHILD | WS_VISIBLE | WS_BORDER,
//设置按钮1坐标
CRect(1200, 10, 1360, 60),
this,
IDC_BUTTON1);
m_button.ShowWindow(SW_SHOWNORMAL);
m_button1.Create("C++",//设置按钮2标题
WS_CHILD | WS_VISIBLE | WS_BORDER,
//设置按钮2坐标
CRect(1200, 70, 1360, 120),
this,
IDC_BUTTON2);
m_button1.ShowWindow(SW_SHOWNORMAL);
//两个按钮的函数实现
void CDrawT12View::OnClickButton1()
{
//按钮1实现
//初始化
a = b = c = d = e = 0;
//打开文件并且操作
CFileDialog fdlg(TRUE, ".dat", "save", OFN_OVERWRITEPROMPT, "数据文件(*.txt)|*.txt|所有文件(*.*)|*.*||", NULL);
//如果成功读取文件
if (fdlg.DoModal() == IDOK)
{
CStdioFile file(fdlg.GetPathName(), CFile::modeRead);
CString cs;
int i = 0;
while (file.ReadString(cs))
{
//当还能读取到行
if (i % 4 == 2)
{
//如果是高数成绩,则转换为数值再判断大小
long long q = _ttoi(cs);
if (q < 60) a++;
else if (q >= 60 && q <= 70) b++;
else if (q > 70 && q <= 80) c++;
else if (q > 80 && q <= 90) d++;
else if (q > 90) e++;
}
i++;
}
}
InvalidateRect(NULL);
}
void CDrawT12View::OnClickButton2()
{
//按钮2实现
//初始化
a = b = c = d = e = 0;
//打开文件并且操作
CFileDialog fdlg(TRUE, ".dat", "save", OFN_OVERWRITEPROMPT, "数据文件(*.txt)|*.txt|所有文件(*.*)|*.*||", NULL);
//如果成功读取文件
if (fdlg.DoModal() == IDOK)
{
CStdioFile file(fdlg.GetPathName(), CFile::modeRead);
CString cs;
int i = 0;
while (file.ReadString(cs))
{
//当还能读取到行
if (i % 4 == 3)
{
//如果是C++成绩,则转换为数值再判断大小
long long q = _ttoi(cs);
if (q < 60) a++;
else if (q >= 60 && q <= 70) b++;
else if (q > 70 && q <= 80) c++;
else if (q > 80 && q <= 90) d++;
else if (q > 90) e++;
}
i++;
}
}
InvalidateRect(NULL);
}
(4)程序运行时的效果图:
(5).实验结果分析,实验收获和体会:
这次mfc实验是对话框实现以及View单文档视图的综合应用
1.这次实验进行初期,我对MFC中工具箱中控件跟实际映射的变量以及函数应用不太熟练,经过实验,我熟悉了MFC的Dlg界面设计,以及各个控件之间的关联绑定。
2.这次实验需要大量使用MFC中各个控件的自带函数(例如读写txt文件,list control的函数方法等等),需要在网上查找资料,经过实验后,使得我对这些函数的使用更加的熟悉了。
3.经过实验,我巩固了头文件的编写与多cpp的编写形式。
4.在cpp文件运用头文件中书写的类时会出现很多问题:无法识别头文件中的类,将头文件stdafx.h书写在最前面include就解决了问题,具体原因未知。
5.试验初期,我运用了CArray(MFC自带的模板容器)来存储学生类,很快就完成完了要求,但是后来因为老师不允许使用STL容器以及其他容器,所以自己写了一个容器,并且通过自己实现了很多类容器的函数方法,让我更加提升了自己的代码能力。
6.实验要求实现MFC单文档内展示两个不同的直方/折现图,因此需要在单文档视图中添加按钮实现,于是我在网上查找资料学习到了在MFC单文档中安置按钮的方法,以及熟悉了在MFC中CBrush(画笔)的函数方法使用。
7.实现排序功能时,我写了多个cmp用于实现多个排序方法,再用algorithm头文件中的sort函数进行快排,实现便捷并且效率高。
8.在实现直方图/折线图的时候,实现界面的标题是未定义标题,觉得有点不太好看(截图在实验报告不美观),因此在网上查找资料,学会了更改标题的方法。
(6)实验的改进意见和建议:
1.实验要求中没有要求到的,我觉得挺重要的按钮:按学号查找,我的想法是在容器类中添加find函数用于查找参数中输入的int学号,再弹出对话框显示该学号学生的所有信息。
2.在学生管理系统中,虽然实验没有要求,但是我添加了反选的按钮,因为我发现在调试的时候,要一个个勾选删除比较麻烦,所以添加反选按钮实现一键删除功能。
3.我认为判断是否学号重复添加的功能是很需要的,因此我在类容器中写了个查找学号是否重复的函数,用于实现这个功能,若重复添加则弹出“学号重复”信息框。
总结:(之前觉得MFC是个上世纪的产物,觉得没用,课也没听,但是为了写这课程设计,还特地去学,枯辽,但是感觉学会了还行8)