程序设计 课程设计实验报告
学院: 计算机科学与网络工程学院 专业班级: XXX 姓名: XXX 学号: 190XXXXXXX
2020.6.29
一、课程设计题目及内容
题目:学生成绩管理系统 设计要求及提示如下: (1)、设计一个学生类Student,包括数据成员:姓名、学号、二门课程(面向对象程序设计、高等数学)的成绩。 (2)、创建一个管理学生的类Management,包括实现学生的数据的增加、删除、修改、按课程成绩排序、保存学生数据到文件及加载文件中的数据等功能。 (3)、创建一个基于对话框的MFC应用程序,程序窗口的标题上有你姓名、学号和应用程序名称。使用(1)和(2)中的类,实现对学生信息和成绩的输入和管理。
(4)、创建一个单文档的MFC应用程序,读取(3)中保存的文件中的学生成绩,分别用直方图和折线方式显示所有学生某课程的成绩分布图。
二、每个功能模块的设计分析及算法描述
各个功能模块的核心功能在Management类完成:
在Management类里声明了一个动态数组all,默认初始化容量为10个,在添加数据时,首先进行数据合法性检查,如果检查不通过直接添加失败,通过则进行添加。如果数组容量满了,将进行自动扩容,扩容的方法是:再开辟一个更大容量的动态数组temp,然后逐一将all中的数据拷贝到temp,拷贝完成之后释放掉all的内存空间,再让all指向temp。如果数组容量再次满了,重复上述操作。删除数据时,需要传入学号,是先逐一遍历all数组中的元素,当发现某个Student与传入的学号相同时,就将这这后面的所有Student向前挪一位,覆盖掉要被删除的Student。修改数据,分为修改姓名、学号、程序课成绩、高数课成绩四个函数,这四个函数都是需要传入学号和修改后的数据,方法和删除数据一样,先根据id找到要修改的Student,然后修改。排序功能:采用冒泡排序。加载文件中的数据:在构造函数里初始化数组all,使用ifstream读取和程序相同目录下的“data.txt”文件,逐个读取后封装成Student对象,添加到数组all。保存数据到文件:在析构函数里进行,先用ofstream打开“data.txt”文件,然后遍历all数组,分别文件输出姓名、学号、程序课成绩、高数课成绩,每个信息之间用空格分隔,每保存完一个Student后回车。 data.txt文件如图:
画统计图在View类完成:
排序之前,从Management类里获取要统计的信息(高数课成绩或者程序课成绩),vector类型,然后再使用这些数据来统计。绘制条形图,先创建一个矩形,把vector中的数据分为5个区间,根据矩形的宽度、高度和区间的最高人数计算每个人应该占多少高度、每个区间占多少宽度,然后根据这些信息来绘制。绘制折线图,也是先创建一个矩形,然后在这个矩形里画线(10行,n列,n为数据的数量),用矩形的宽度/数据的数量可以得到每个点相差的距离,用矩形的高度*数据的值/100得到高度,然后每个点的信息都记录在数组里,最后交给Polyline函数画线。
查找功能:首先要检查输入内容的合法性(分数区间不能为空,最大值不能大于100,最小值不能小于0,且最小值不能比最大值大),借助vector容器,遍历Management的all数组,如果满足条件,则将改Student添加到vector容器中,最后遍历完之后输入vector容器保存的结果。模糊查询的方法是用CString的Find()函数,如果返回结果不为-1,则代表这个CString里包含这个字符串。
三、程序中使用的数据及主要符号说明
Student 类:
CString m_name;//姓名
CString m_id;//学号(唯一)
int score1;//程序课成绩
int score2;//高数课成绩
Management 类:
Student* all; //存放学生数据的数组
int capacity; //数组当前容量
int size; //数组当前大小
(extern) Management m; //Management对象,在View.cpp和ADD.cpp都有出现,为了在两个cpp共用一个对象,所以在其中一个地方加了extern
数据管理的对话框:
ADD; //添加数据的对话框,类名为ADD
CString m_name; //输入姓名的编辑框
CString m_id;//输入学号的编辑框
int score1;//输入程序课成绩的编辑框
int score2;//输入高数课成绩的编辑框
int Search_Score1_Min; //数据查找时,需要输入的程序课成绩最小值
int Search_Score1_Max; //数据查找时,需要输入的程序课成绩最大值
int Search_Score2_Min; //数据查找时,需要输入的高数课成绩最小值
int Search_Score2_Max; //数据查找时,需要输入的高数课成绩最大值
CString Search_Name; //数据查找时,需要输入的姓名
CString Search_Id; //数据查找时,需要输入的程序课成绩学号
四、带有详细注释的自己编写的源程序
#pragma once
class Student {
public:
CString m_name
;
CString m_id
;
int score1
;
int score2
;
Student(const CString
& m_name
, const CString
& m_id
, int score1
, int score2
);
Student();
};
Student
.cpp
#include "pch.h"
#include "Student.h"
Student
::Student(const CString
& m_name
, const CString
& m_id
, int score1
, int score2
)
: m_name(m_name
),
m_id(m_id
),
score1(score1
),
score2(score2
) {
}
Student
::Student() {
}
#pragma once
#include<fstream>
#include "Student.h"
#include <string>
#include "ADD.h"
#include <vector>
using namespace std
;
constexpr auto INIT_SIZE
= 10;
constexpr auto INCREASE_SIZE
= 10;
class Management {
public:
Student
* all
= NULL;
int capacity
= 0;
int size
= 0;
void add(Student stu
);
bool del(CString id
);
bool hasId(CString id
);
void sortByScore1(bool = false);
void sortByScore2(bool = false);
void sortById(bool = false);
CString
getName(CString id
);
int getS1(CString id
);
int getS2(CString id
);
bool changeData(CString oldId
, CString newName
, CString newId
, int S1
, int S2
) const;
Management();
~Management();
vector
<int> getMathScores() const;
vector
<int> getProgrammingScores() const;
};
#include "pch.h"
#include "Management.h"
void Management
::add(Student stu
) {
if (size
>= capacity
) {
capacity
+= INCREASE_SIZE
;
Student
* temp
= new Student
[capacity
];
for (int i
= 0; i
< size
; i
++) {
temp
[i
] = all
[i
];
}
delete[] all
;
all
= temp
;
}
all
[size
++] = stu
;
}
bool Management
::del(CString id
) {
for (int i
= 0; i
< size
; i
++) {
if (id
== all
[i
].m_id
) {
for (int j
= i
; j
< size
- 1; ++j
) {
all
[j
] = all
[j
+ 1];
}
--size
;
return true;
}
}
return false;
}
bool Management
::hasId(CString id
) {
for (int i
= 0; i
< size
; i
++) {
if (id
== all
[i
].m_id
)
return true;
}
return false;
}
void Management
::sortByScore1(bool tag
) {
if (tag
) {
for (int i
= 0; i
< size
; i
++) {
for (int j
= 0; j
< size
- i
- 1; ++j
) {
if (all
[j
].score1
> all
[j
+ 1].score1
) {
Student temp
= all
[j
];
all
[j
] = all
[j
+ 1];
all
[j
+ 1] = temp
;
}
}
}
}else {
for (int i
= 0; i
< size
; i
++) {
for (int j
= 0; j
< size
- i
- 1; ++j
) {
if (all
[j
].score1
< all
[j
+ 1].score1
) {
Student temp
= all
[j
];
all
[j
] = all
[j
+ 1];
all
[j
+ 1] = temp
;
}
}
}
}
}
void Management
::sortByScore2(bool tag
) {
if (tag
) {
for (int i
= 0; i
< size
; i
++) {
for (int j
= 0; j
< size
- i
- 1; ++j
) {
if (all
[j
].score2
> all
[j
+ 1].score2
) {
Student temp
= all
[j
];
all
[j
] = all
[j
+ 1];
all
[j
+ 1] = temp
;
}
}
}
}
else {
for (int i
= 0; i
< size
; i
++) {
for (int j
= 0; j
< size
- i
- 1; ++j
) {
if (all
[j
].score2
< all
[j
+ 1].score2
) {
Student temp
= all
[j
];
all
[j
] = all
[j
+ 1];
all
[j
+ 1] = temp
;
}
}
}
}
}
void Management
::sortById(bool tag
)
{
if (tag
) {
for (int i
= 0; i
< size
; i
++) {
for (int j
= 0; j
< size
- i
- 1; ++j
) {
if (all
[j
].m_id
> all
[j
+ 1].m_id
) {
Student temp
= all
[j
];
all
[j
] = all
[j
+ 1];
all
[j
+ 1] = temp
;
}
}
}
}
else {
for (int i
= 0; i
< size
; i
++) {
for (int j
= 0; j
< size
- i
- 1; ++j
) {
if (all
[j
].m_id
< all
[j
+ 1].m_id
) {
Student temp
= all
[j
];
all
[j
] = all
[j
+ 1];
all
[j
+ 1] = temp
;
}
}
}
}
}
CString Management
::getName(CString id
) {
for (int i
= 0; i
< size
; i
++) {
if (id
== all
[i
].m_id
)
return all
[i
].m_name
;
}
return TEXT("");
}
int Management
::getS1(CString id
) {
for (int i
= 0; i
< size
; i
++) {
if (id
== all
[i
].m_id
)
return all
[i
].score1
;
}
return 0;
}
int Management
::getS2(CString id
) {
for (int i
= 0; i
< size
; i
++) {
if (id
== all
[i
].m_id
)
return all
[i
].score2
;
}
return 0;
}
bool Management
::changeData(CString oldId
, CString newName
, CString newId
, int S1
, int S2
) const {
for (int i
= 0; i
< size
; i
++) {
if (oldId
== all
[i
].m_id
) {
all
[i
].m_name
= newName
;
all
[i
].m_id
= newId
;
all
[i
].score1
= S1
;
all
[i
].score2
= S2
;
return true;
}
}
return false;
}
Management
::Management() {
all
= new Student
[INIT_SIZE
];
capacity
= INIT_SIZE
;
ifstream
ifs("data.txt", ios
::in
);
if (ifs
.is_open() && ifs
.peek() != EOF) {
while (ifs
.peek() != EOF) {
string name
, id
;
int score1
, score2
;
ifs
>> name
>> id
>> score1
>> score2
;
CString
m_name(name
.c_str());
CString
m_id(id
.c_str());
Student
stu(m_name
, m_id
, score1
, score2
);
add(stu
);
}
}
ifs
.close();
}
Management
::~Management() {
ofstream
ofs("data.txt", ios
::out
);
if (ofs
.is_open()) {
for (int i
= 0; i
< size
; i
++) {
Student stu
= all
[i
];
string
name(CT2A(all
[i
].m_name
.GetBuffer()));
string
id(CT2A(all
[i
].m_id
.GetBuffer()));
ofs
<< name
<< " " << id
<< " " << stu
.score1
<< " " << stu
.score2
;
if (i
!= size
- 1) ofs
<< endl
;
}
}
ofs
.close();
delete[] all
;
}
vector
<int> Management
::getMathScores() const {
vector
<int> datas
;
for (int i
= 0; i
< size
; i
++) {
datas
.push_back(all
[i
].score2
);
}
return datas
;
}
vector
<int> Management
::getProgrammingScores() const {
vector
<int> datas
;
for (int i
= 0; i
< size
; i
++) {
datas
.push_back(all
[i
].score1
);
}
return datas
;
}
#pragma once
class ADD : public CDialogEx
{
DECLARE_DYNAMIC(ADD
)
public:
ADD(CWnd
* pParent
= nullptr);
virtual ~ADD();
#ifdef AFX_DESIGN_TIME
enum { IDD
= ADD_STUDENT
};
#endif
protected:
virtual void DoDataExchange(CDataExchange
* pDX
);
DECLARE_MESSAGE_MAP()
public:
CString m_name
;
CString m_id
;
int score1
;
int score2
;
afx_msg
void OnBnClickedButton1();
CListBox DATA
;
afx_msg
void OnBnClickedButton6();
afx_msg
void OnBnClickedButton2();
afx_msg
void OnLbnSelchangeList1();
afx_msg
void OnBnClickedButton3();
afx_msg
void OnBnClickedButton4();
afx_msg
void OnBnClickedButton5();
afx_msg
void OnActivate(UINT nState
, CWnd
* pWndOther
, BOOL bMinimized
);
afx_msg
void OnBnClickedButton7();
afx_msg
void OnBnClickedButton8();
afx_msg
void OnBnClickedButton9();
afx_msg
void OnBnClickedButton10();
afx_msg
void OnBnClickedButton11();
afx_msg
void OnBnClickedButton12();
afx_msg
int OnCreate(LPCREATESTRUCT lpCreateStruct
);
int Search_Score1_Min
;
int Search_Score1_Max
;
int Search_Score2_Min
;
int Search_Score2_Max
;
CString Search_Name
;
CString Search_Id
;
afx_msg
void OnBnClickedButton13();
};
#include "pch.h"
#include "StudentManagerSystem.h"
#include "afxdialogex.h"
#include "ADD.h"
#include "ChildView.h"
#include<ctime>
#include <vector>
Management m
;
IMPLEMENT_DYNAMIC(ADD
, CDialogEx
)
ADD
::ADD(CWnd
* pParent
)
: CDialogEx(ADD_STUDENT
, pParent
)
, m_name(_T(""))
, m_id(_T(""))
, score1(60)
, score2(60), Search_Score1_Min(0)
, Search_Score1_Max(100)
, Search_Score2_Min(0)
, Search_Score2_Max(100)
, Search_Name(_T(""))
, Search_Id(_T("")) {
}
ADD
::~ADD() = default;
void ADD
::DoDataExchange(CDataExchange
* pDX
) {
CDialogEx
::DoDataExchange(pDX
);
DDX_Text(pDX
, IDC_EDIT1
, m_name
);
DDX_Text(pDX
, IDC_EDIT2
, m_id
);
DDX_Text(pDX
, IDC_EDIT3
, score1
);
DDX_Text(pDX
, IDC_EDIT4
, score2
);
DDX_Control(pDX
, IDC_LIST1
, DATA
);
DDX_Text(pDX
, IDC_EDIT7
, Search_Score1_Min
);
DDX_Text(pDX
, IDC_EDIT8
, Search_Score1_Max
);
DDX_Text(pDX
, IDC_EDIT9
, Search_Score2_Min
);
DDX_Text(pDX
, IDC_EDIT10
, Search_Score2_Max
);
DDX_Text(pDX
, IDC_EDIT5
, Search_Name
);
DDX_Text(pDX
, IDC_EDIT6
, Search_Id
);
}
BEGIN_MESSAGE_MAP(ADD
, CDialogEx
)
ON_BN_CLICKED(IDC_BUTTON1
, &ADD
::OnBnClickedButton1
)
ON_BN_CLICKED(IDC_BUTTON6
, &ADD
::OnBnClickedButton6
)
ON_BN_CLICKED(IDC_BUTTON2
, &ADD
::OnBnClickedButton2
)
ON_LBN_SELCHANGE(IDC_LIST1
, &ADD
::OnLbnSelchangeList1
)
ON_BN_CLICKED(IDC_BUTTON3
, &ADD
::OnBnClickedButton3
)
ON_BN_CLICKED(IDC_BUTTON4
, &ADD
::OnBnClickedButton4
)
ON_BN_CLICKED(IDC_BUTTON5
, &ADD
::OnBnClickedButton5
)
ON_WM_ACTIVATE()
ON_BN_CLICKED(IDC_BUTTON7
, &ADD
::OnBnClickedButton7
)
ON_BN_CLICKED(IDC_BUTTON8
, &ADD
::OnBnClickedButton8
)
ON_BN_CLICKED(IDC_BUTTON9
, &ADD
::OnBnClickedButton9
)
ON_BN_CLICKED(IDC_BUTTON10
, &ADD
::OnBnClickedButton10
)
ON_BN_CLICKED(IDC_BUTTON11
, &ADD
::OnBnClickedButton11
)
ON_BN_CLICKED(IDC_BUTTON12
, &ADD
::OnBnClickedButton12
)
ON_WM_CREATE()
ON_BN_CLICKED(IDC_BUTTON13
, &ADD
::OnBnClickedButton13
)
END_MESSAGE_MAP()
void ADD
::OnBnClickedButton1() {
CString cstr1
;
CString cstr2
;
CString cstr3
;
CString cstr4
;
GetDlgItem(IDC_EDIT1
)->GetWindowText(cstr1
);
GetDlgItem(IDC_EDIT2
)->GetWindowText(cstr2
);
GetDlgItem(IDC_EDIT3
)->GetWindowText(cstr3
);
GetDlgItem(IDC_EDIT4
)->GetWindowText(cstr4
);
if (cstr1
== _T("") || cstr2
== _T("") || cstr3
== _T("") || cstr4
== _T("")) {
MessageBox(TEXT("输入的内容不能为空!"));
return;
}
UpdateData(TRUE
);
int a
= m_name
.Find(TEXT(" "));
int b
= m_id
.Find(TEXT(" "));
if (a
!= -1 || b
!= -1) {
MessageBox(TEXT("输入的内容请不要包含空格!"));
return;
}
if (m_id
.GetLength() == 10) {
for (int i
= 0; i
< 10; ++i
) {
if (!(m_id
.GetAt(i
) >= '0' && m_id
.GetAt(i
) <= '9')) {
MessageBox(TEXT("学号必须由数字组成"));
return;
}
}
}
else {
MessageBox(TEXT("学号的长度必须为10"));
return;
}
if (score1
< 0 || score1
> 100 || score2
< 0 || score2
> 100) {
MessageBox(TEXT("分数必须在0到100分之间"));
return;
}
if (m
.hasId(m_id
)) {
MessageBox(TEXT("该学号已重复"));
return;
}
Student
stu(m_name
, m_id
, score1
, score2
);
m
.add(stu
);
DATA
.AddString(m_id
+ "==" + m_name
);
MessageBox(TEXT("添加成功"));
DATA
.SetCurSel(DATA
.GetCount() - 1);
OnLbnSelchangeList1();
}
void ADD
::OnBnClickedButton2() {
CString id
;
int i
= DATA
.GetCurSel();
if (i
!= -1) {
DATA
.GetText(i
, id
);
const int index
= id
.Find(_T("=="));
id
= id
.Mid(0, index
);
if (m
.del(id
) ) {
DATA
.DeleteString(i
);
MessageBox(TEXT("删除成功"));
DATA
.SetCurSel(i
== 0 ? 0 : i
- 1);
OnLbnSelchangeList1();
}
else {
MessageBox(TEXT("该学号不存在!可能是由于数据未更新所致,请刷新列表!"));
}
}
else {
MessageBox(TEXT("当前没有选中任何学生,请先在左边列表中选择!"));
}
}
void ADD
::OnLbnSelchangeList1() {
int i
= DATA
.GetCurSel();
if (i
!= -1) {
CString id
;
DATA
.GetText(i
, id
);
i
= id
.Find(_T("=="));
id
= id
.Mid(0, i
);
if (m
.hasId(id
)) {
m_name
= m
.getName(id
);
m_id
= id
;
score1
= m
.getS1(id
);
score2
= m
.getS2(id
);
UpdateData(FALSE
);
}
else {
MessageBox(TEXT("该学号不存在!可能是由于数据未更新所致,请刷新列表!"));
}
}
}
void ADD
::OnBnClickedButton3() {
CString id
;
int i
= DATA
.GetCurSel();
if (i
== -1) {
MessageBox(TEXT("当前没有选中任何学生,请先在左边列表中选择!"));
return;
}
DATA
.GetText(i
, id
);
const int index
= id
.Find(_T("=="));
id
= id
.Mid(0, index
);
CString cstr1
;
CString cstr2
;
CString cstr3
;
CString cstr4
;
GetDlgItem(IDC_EDIT1
)->GetWindowText(cstr1
);
GetDlgItem(IDC_EDIT2
)->GetWindowText(cstr2
);
GetDlgItem(IDC_EDIT3
)->GetWindowText(cstr3
);
GetDlgItem(IDC_EDIT4
)->GetWindowText(cstr4
);
if (cstr1
== _T("") || cstr2
== _T("") || cstr3
== _T("") || cstr4
== _T("")) {
MessageBox(TEXT("输入的内容不能为空!"));
return;
}
UpdateData(TRUE
);
int a
= m_name
.Find(TEXT(" "));
int b
= m_id
.Find(TEXT(" "));
if (a
!= -1 || b
!= -1) {
MessageBox(TEXT("输入的内容请不要包含空格!"));
return;
}
if (m_id
.GetLength() == 10) {
for (int i
= 0; i
< 10; ++i
) {
if (!(m_id
.GetAt(i
) >= '0' && m_id
.GetAt(i
) <= '9')) {
MessageBox(TEXT("学号必须由数字组成"));
return;
}
}
}
else {
MessageBox(TEXT("学号的长度必须为10"));
return;
}
if (score1
< 0 || score1
> 100 || score2
< 0 || score2
> 100) {
MessageBox(TEXT("分数必须在0到100分之间"));
return;
}
if (m_id
!= id
&& m
.hasId(m_id
)) {
MessageBox(TEXT("该学号已重复"));
return;
}
if (m
.changeData(id
, m_name
, m_id
, score1
, score2
)) {
OnBnClickedButton6();
MessageBox(TEXT("修改成功"));
for (int j
= 0; j
< DATA
.GetCount(); j
++) {
CString cs
;
DATA
.GetText(j
, cs
);
if (cs
.Mid(0, cs
.Find(_T("=="))) == m_id
) {
DATA
.SetCurSel(j
);
break;
}
}
}
else {
MessageBox(TEXT("该学号不存在!可能是由于数据未更新所致,请刷新列表!"));
}
}
void ADD
::OnBnClickedButton4() {
m
.sortByScore1();
CString id
;
int i
= DATA
.GetCurSel();
OnBnClickedButton6();
if (i
!= -1) {
DATA
.GetText(i
, id
);
for (int j
= 0; j
< DATA
.GetCount(); j
++) {
CString cs
;
DATA
.GetText(j
, cs
);
if (cs
.Mid(0, cs
.Find(_T("=="))) == m_id
) {
DATA
.SetCurSel(j
);
break;
}
}
}
OnLbnSelchangeList1();
}
void ADD
::OnBnClickedButton5() {
m
.sortByScore2();
CString id
;
int i
= DATA
.GetCurSel();
OnBnClickedButton6();
if (i
!= -1) {
DATA
.GetText(i
, id
);
for (int j
= 0; j
< DATA
.GetCount(); j
++) {
CString cs
;
DATA
.GetText(j
, cs
);
if (cs
.Mid(0, cs
.Find(_T("=="))) == m_id
) {
DATA
.SetCurSel(j
);
break;
}
}
}
OnLbnSelchangeList1();
}
void ADD
::OnBnClickedButton6() {
DATA
.ResetContent();
for (int i
= 0; i
< m
.size
; i
++) {
CString str
;
str
= m
.all
[i
].m_id
;
str
+= "==";
str
+= m
.all
[i
].m_name
;
DATA
.AddString(str
);
}
}
void ADD
::OnActivate(UINT nState
, CWnd
* pWndOther
, BOOL bMinimized
) {
CDialogEx
::OnActivate(nState
, pWndOther
, bMinimized
);
srand((unsigned long)time(NULL));
OnBnClickedButton6();
}
void ADD
::OnBnClickedButton7() {
m
.sortByScore1(true);
CString id
;
int i
= DATA
.GetCurSel();
OnBnClickedButton6();
if (i
!= -1) {
DATA
.GetText(i
, id
);
for (int j
= 0; j
< DATA
.GetCount(); j
++) {
CString cs
;
DATA
.GetText(j
, cs
);
if (cs
.Mid(0, cs
.Find(_T("=="))) == m_id
) {
DATA
.SetCurSel(j
);
break;
}
}
}
OnLbnSelchangeList1();
}
void ADD
::OnBnClickedButton8() {
m
.sortByScore2(true);
CString id
;
int i
= DATA
.GetCurSel();
OnBnClickedButton6();
if (i
!= -1) {
DATA
.GetText(i
, id
);
for (int j
= 0; j
< DATA
.GetCount(); j
++) {
CString cs
;
DATA
.GetText(j
, cs
);
if (cs
.Mid(0, cs
.Find(_T("=="))) == m_id
) {
DATA
.SetCurSel(j
);
break;
}
}
}
OnLbnSelchangeList1();
}
void ADD
::OnBnClickedButton9() {
m
.sortById();
CString id
;
int i
= DATA
.GetCurSel();
OnBnClickedButton6();
if (i
!= -1) {
DATA
.GetText(i
, id
);
for (int j
= 0; j
< DATA
.GetCount(); j
++) {
CString cs
;
DATA
.GetText(j
, cs
);
if (cs
.Mid(0, cs
.Find(_T("=="))) == m_id
) {
DATA
.SetCurSel(j
);
break;
}
}
}
OnLbnSelchangeList1();
}
void ADD
::OnBnClickedButton10() {
m
.sortById(true);
CString id
;
int i
= DATA
.GetCurSel();
OnBnClickedButton6();
if (i
!= -1) {
DATA
.GetText(i
, id
);
for (int j
= 0; j
< DATA
.GetCount(); j
++) {
CString cs
;
DATA
.GetText(j
, cs
);
if (cs
.Mid(0, cs
.Find(_T("=="))) == m_id
) {
DATA
.SetCurSel(j
);
break;
}
}
}
OnLbnSelchangeList1();
}
void ADD
::OnBnClickedButton11() {
UpdateData(TRUE
);
score1
= rand() % 101;
UpdateData(FALSE
);
}
void ADD
::OnBnClickedButton12() {
UpdateData(TRUE
);
score2
= rand() % 101;
UpdateData(FALSE
);
}
int ADD
::OnCreate(LPCREATESTRUCT lpCreateStruct
) {
if (CDialogEx
::OnCreate(lpCreateStruct
) == -1)
return -1;
return 0;
}
void ADD
::OnBnClickedButton13() {
CString cstr1
;
CString cstr2
;
CString cstr3
;
CString cstr4
;
GetDlgItem(IDC_EDIT7
)->GetWindowText(cstr1
);
GetDlgItem(IDC_EDIT8
)->GetWindowText(cstr2
);
GetDlgItem(IDC_EDIT9
)->GetWindowText(cstr3
);
GetDlgItem(IDC_EDIT10
)->GetWindowText(cstr4
);
if (cstr1
== _T("") || cstr2
== _T("") || cstr3
== _T("") || cstr4
== _T("")) {
MessageBox(TEXT("输入的成绩的范围不能为空!"));
return;
}
UpdateData(TRUE
);
if (Search_Score1_Max
> 100 || Search_Score1_Max
< 0 || Search_Score1_Min
> 100 || Search_Score1_Min
< 0 ||
Search_Score2_Max
> 100 || Search_Score2_Max
< 0 || Search_Score2_Min
> 100 || Search_Score2_Min
< 0) {
MessageBox(TEXT("输入的成绩的范围必须在区间[0,100]内!"));
return;
}
if (Search_Score1_Min
> Search_Score1_Max
|| Search_Score2_Min
> Search_Score2_Max
) {
MessageBox(TEXT("输入的成绩最小值不能比最大值大!"));
return;
}
std
::vector
<Student
> result
;
for (int i
= 0; i
< m
.size
; ++i
) {
Student stu
= m
.all
[i
];
if (stu
.m_name
.Find(Search_Name
) != -1 &&
stu
.m_id
.Find(Search_Id
) != -1 &&
stu
.score1
>= Search_Score1_Min
&&
stu
.score1
<= Search_Score1_Max
&&
stu
.score2
>= Search_Score2_Min
&&
stu
.score2
<= Search_Score2_Max
) {
result
.push_back(stu
);
}
}
CString str
;
for (auto stu
: result
) {
CString cScore1
;
CString cScore2
;
cScore1
.Format(_T("%d"), stu
.score1
);
cScore2
.Format(_T("%d"), stu
.score2
);
str
+= _T("学生姓名:") + stu
.m_name
+ _T("\t学号:") + stu
.m_id
+ _T("\t程序课成绩:") + cScore1
+ _T("\t高数课成绩:") + cScore2
+ _T("\n");
}
CString cLength
;
cLength
.Format(_T("%d"), result
.size());
MessageBox(str
,_T("共查询到") + cLength
+ _T("条结果"));
}
#pragma once
#include "ADD.h"
#include "Management.h"
#include<vector>
using namespace std
;
class CChildView : public CWnd
{
public:
CChildView();
ADD add
;
public:
public:
protected:
virtual BOOL
PreCreateWindow(CREATESTRUCT
& cs
);
public:
virtual ~CChildView();
protected:
afx_msg
void OnPaint();
DECLARE_MESSAGE_MAP()
public:
afx_msg
void OnLButtonDown(UINT nFlags
, CPoint point
);
void DrawBar(CDC
*dc
, std
::vector
<int> db
,bool left
= true) const;
void DrawLine(CDC
*dc
, std
::vector
<int> db
,bool left
= true) const;
void OnDraw(CDC
* pDC
);
};
#include "pch.h"
#include "framework.h"
#include "ChildView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
extern Management m
;
CChildView
::CChildView() {
}
CChildView
::~CChildView() {
}
BEGIN_MESSAGE_MAP(CChildView
, CWnd
)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_DRAWITEM()
ON_WM_DRAWITEM()
END_MESSAGE_MAP()
BOOL CChildView
::PreCreateWindow(CREATESTRUCT
& cs
) {
if (!CWnd
::PreCreateWindow(cs
))
return FALSE
;
cs
.dwExStyle
|= WS_EX_CLIENTEDGE
;
cs
.style
&= ~WS_BORDER
;
cs
.lpszClass
= AfxRegisterWndClass(CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
,
::LoadCursor(nullptr, IDC_ARROW
), reinterpret_cast<HBRUSH
>(COLOR_WINDOW
+ 1),
nullptr);
return TRUE
;
}
void CChildView
::OnPaint() {
CPaintDC
dc(this);
OnDraw(&dc
);
}
void CChildView
::DrawBar(CDC
* dc
, std
::vector
<int> db
,bool left
) const {
CRect rc
;
GetClientRect(rc
);
rc
.DeflateRect(30, 15, 10, rc
.Height() / 2+15);
if(left
) {
rc
.right
= rc
.Width() / 2 - 15;
dc
->TextOutW(rc
.left
, 0, TEXT("高数课成绩统计"));
}else {
rc
.left
= rc
.Width() / 2 + 15;
dc
->TextOutW(rc
.left
, 0, TEXT("程序课成绩统计"));
}
CBrush
brush1(HS_BDIAGONAL
, RGB(96, 192, 255));
CBrush
brush2(HS_FDIAGONAL
, RGB(96, 192, 255));
CPen
pen(PS_INSIDEFRAME
, 2, RGB(96, 192, 255));
int n
= 5;
int width
= rc
.Width() / n
;
int s
[] = {0, 0, 0, 0, 0};
for (int i
= 0; i
< db
.size(); i
++) {
if (db
[i
] < 60) s
[0] ++;
else if (db
[i
] >= 60 && db
[i
] < 70) s
[1]++;
else if (db
[i
] >= 70 && db
[i
] < 80) s
[2]++;
else if (db
[i
] >= 80 && db
[i
] < 90) s
[3]++;
else s
[4]++;
}
int max_s
= s
[0];
for (int i
= 0; i
< n
; i
++)
if (max_s
< s
[i
]) max_s
= s
[i
];
int per_Height
= rc
.Height() / max_s
;
CRect
ps_rect(rc
);
ps_rect
.right
= ps_rect
.left
+ width
;
dc
->SelectObject(&pen
);
CString str
[5] = {_T("<60"),_T("60-70"),_T("70-80"),_T("80-90"),_T(">=90")};
for (int i
= 0; i
< n
; i
++) {
ps_rect
.top
= ps_rect
.bottom
- per_Height
* s
[i
];
if (i
% 2) dc
->SelectObject(&brush2
);
else dc
->SelectObject(&brush1
);
dc
->Rectangle(ps_rect
);
if (s
[i
] > 0) {
CString str1
;
str1
.Format(_T("%d人"), s
[i
]);
dc
->DrawText(str1
, ps_rect
, DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
);
}
dc
->TextOutW((ps_rect
.left
+ ps_rect
.right
) / 2 - 15, ps_rect
.bottom
+5 , str
[i
]);
ps_rect
.OffsetRect(width
, 0);
}
}
void CChildView
::DrawLine(CDC
* dc
, std
::vector
<int> db
,bool left
) const {
CRect rc
;
GetClientRect(rc
);
rc
.DeflateRect(30, rc
.Height() / 2 + 15, 10, 15);
if (left
) {
rc
.right
= rc
.Width() / 2 - 15;
}
else {
rc
.left
= rc
.Width() / 2 + 15;
}
int gridXnums
= db
.size();
int gridYnums
= 10;
int dx
= rc
.Width() / gridXnums
;
int dy
= rc
.Height() / gridYnums
;
CRect
gridRect(rc
.left
, rc
.top
, rc
.left
+ dx
* gridXnums
, rc
.top
+ dy
* gridYnums
);
CPen
gridPen(PS_DASHDOTDOT
, 1, RGB(96, 192, 255));
dc
->SelectObject(&gridPen
);
for (int i
= 0; i
<= gridXnums
; i
++) {
dc
->MoveTo(gridRect
.left
+ i
* dx
, gridRect
.bottom
);
dc
->LineTo(gridRect
.left
+ i
* dx
, gridRect
.top
);
}
for (int j
= 0; j
<= gridYnums
; j
++) {
dc
->MoveTo(gridRect
.left
, gridRect
.top
+ j
* dy
);
dc
->LineTo(gridRect
.right
, gridRect
.top
+ j
* dy
);
CString str
;
str
.Format(_T("%d"), 100 - 10 * j
);
dc
->TextOutW(rc
.left
- 25, gridRect
.top
+ j
* dy
- 10, str
);
}
gridPen
.Detach();
CPen
linePen(PS_SOLID
, 2, RGB(255, 0, 0));
dc
->SelectObject(&linePen
);
int nCount
= db
.size();
int deta
= gridRect
.Width() / nCount
;
POINT
* pt
= new POINT
[nCount
];
for (int i
= 0; i
< nCount
; i
++) {
pt
[i
].x
= gridRect
.left
+ i
* deta
;
pt
[i
].y
= gridRect
.bottom
- (int)(db
[i
] / 100.0 * gridRect
.Height());
CString score
;
score
.Format(_T("%d"), db
[i
]);
}
dc
->Polyline(pt
, nCount
);
delete[] pt
;
pt
= nullptr;
}
void CChildView
::OnDraw(CDC
* pDC
) {
vector
<int> programmingScores
= m
.getProgrammingScores();
vector
<int> mathScores
= m
.getMathScores();
if (!mathScores
.empty() && !programmingScores
.empty()) {
DrawBar(pDC
, mathScores
,true);
DrawBar(pDC
, programmingScores
,false);
DrawLine(pDC
, mathScores
,true);
DrawLine(pDC
, programmingScores
,false);
}
}
void CChildView
::OnLButtonDown(UINT nFlags
, CPoint point
) {
CWnd
::OnLButtonDown(nFlags
, point
);
add
.DoModal();
Invalidate();
OnPaint();
}
五、程序运行时的效果图
统计图
数据管理
添加学生时,姓名、学号或成绩为空
添加学生时,学号不是数字或者长度不为10
如果姓名或学号输入了空格
输入的成绩越界
成功添加数据
成功删除数据
成功修改数据(容错条件和添加数据一样,不再演示)
按成绩排序(从折线图看效果)
数据查询,查询全部
数据查询,查询高数课和程序课成绩都大于80分的
数据查询,查询姓名里带有“刘”字的
查询学号里带有2的
六、实验结果分析
我在实验中遇到的问题和解决方法
对话框初始化时程序崩溃,如下图:
本来我是打算在对话框一打开就自动加载数据,而不需要手动加载数据,所以我在对话框的OnCreate()函数里进行列表的初始化操作,才会发生这样子的程序奔溃,经过我后面的尝试,把初始化代码放到OnActivate()函数里才解决问题。问题产生的原因我不太清楚,我个人猜测是OnCreate函数在窗口还没完全显示的时候执行,而OnActivate会在窗口显示完成之后才执行,应该是因为窗口还没显示的时候把数据添加到列表导致的问题。
Management对象的问题 因为我所有的学生数据都存放在Management里的all数组里,所以我需要在对话框ADD类和单文档绘图的View类里共用一个Management对象,一开始我是把对象创建在.h文件中,结果造成了一些错误(无法解析的外部符号),于是我按照网上的办法,把对象放在.cpp文件中。但是新的问题出现了,我本以为多个cpp文件如果共用一个变量,只需在一个.cpp中包含另一个.cpp就行了,结果我在一个debug中,发现Management对象竟然创建了5次,这时我才意识到多个cpp中的Management并不是共用的,后来我的解决办法是在View.cpp中的Management加extern修饰符。
数据文件保存和读取问题 我在Management类的构造和析构函数中对数据文件进行读取和保存,我每向文件输出完一条学生信息,我都会换行,但是在读取的时候会莫名地多出一条空白数据,经过我的研究,是因为输出最后一行数据再回车导致的问题。我的解决办法是在向文件输出时加个if判断,如果这条数据不是最后一条数据,则再输出回车。
关于成绩输入框的弹窗问题 我成绩输入框创建变量的时候,类型设置为int,当执行UpdataData函数的时候,如果里面不是数字或者为空,会弹出这样的一个框
本来这样的提示是没什么问题的,但是弹出框了之后,如果是添加数据,则照样会添加成功,只是成绩都是默认值0,但这样子就不符合逻辑了!我的解决办法是:先在把编辑框的Number属性改成True,保证了输入框无法输入数字,然后就还剩输入为空的情况,我就通过以下代码,在UpdateData之前检查输入是否为空:
收获
更加熟悉MFC编程,学会了在View类的绘图方法,学会了基于对话框的很多内容。重新复习了上个学期所学的冒泡排序、动态数组等知识。领悟了CString与string的区别,并学会了CString与string的互相转换、其他基本数据类型转换成CString。掌握了面向对象的编程思想。