学生成绩管理系统–C++语言实现

  • Post author:
  • Post category:其他




注:该项目为图形编程。采用C++面向对象程序设计


一.环境准备


开发环境:Visual Studio 2019,easyx图形库

easyx下载官网:




EasyX Graphics Library for C++


EasyX Graphics Library 是针对 Visual C++ 的绘图库,支持 VC6.0 ~ VC2019,简单易用,学习成本极低,应用领域广泛。目前已有许多大学将 EasyX 应用在教学当中。



https://easyx.cn/


easyx使用文档:




EasyX 文档 – 函数说明



https://docs.easyx.cn/zh-cn/reference



二.系统功能列表

功能列表:

  1. 查看所有学生信息
  2. 添加学生信息
  3. 删除学生信息
  4. 查找某学生,显示其全部信息
  5. 修改学生信息
  6. 对学生成绩总和进行排序
  7. 退出程序存档
  8. 按Esc键可以随时返回封面


三.程序分解阐释

因为学生成绩管理系统需要处理大量学生的信息,所以采用了

面向对象程序设计

,设计了两个类,

student类用来定义学生的个人信息,还定义了Management类公有继承于student类,Management类的成员函数可以访问student类中的成员变量。

在Management类中定义了一个vector数组,用来存储学生信息。Management类中一共定义了八个成员函数。


1.student类的定义

#pragma once
#include<string>
class student
{
public:
	student();
	student(const std::string& name, const std::string& gender, int Class, int StuNum, int math, int English, int program);
	std::string f();
	void display(int m);
	std::string name, gender;          //定义学生信息有关变量
	int Class, StuNum, math,English,program;
};


2.Management类的定义

#pragma once
#include "student.h"
#include<vector>
#include<string>
using namespace std;
class Management :
    public student             //公有继承,可以访问student内的公有成员
{
public:
	Management();
	void displayall();  //展示全部
	void add();         //添加学生信息
	void Erase();       //删除学生信息
	void modify();      //修改学生信息
	void find();        //查找学生信息
	void Sort();        //学生成绩排序
	void readData(const string& fileName, char a[]);
	void writeData(const string& fileName);
	vector<student>Stu;         //定义一个student类型的动态数组,大小不受限制
	string TableHeader;
	string tablebody;
};

3

.student类成员函数的类外定义

#include "student.h"
#include<graphics.h>
#include<iostream>
#include<sstream>    
#include<string>
#include<iomanip>
using namespace std;

student::student() :Class(0), StuNum(0), math(0), English(0), program(0)
{
}

student::student( const std::string& name, const std::string& gender,int Class,int StuNum,int math, int English, int program)
	:name(name),gender(gender),Class(Class),StuNum(StuNum),math(math),English(English), program(program) 
{
}


string student::f()              //将int型变量转化为字符数组并写入文件
{
	stringstream ss;              
	ss << this->name <<'\t'<< this->gender <<'\t'<< this->Class <<'\t'<< this->StuNum <<'\t'<< this->math <<'\t'<<this->English <<'\t'<< this->program << endl;
	return ss.str();
}
   int y = 30;

void student::display(int m)
{   
	stringstream ss;
	ss<<Class<<"    "<<StuNum<<setw(6)<<math<<setw(7)<<English<<setw(8)<<program<<setw(10)<<math+English+program;      
	string tablebody=ss.str();      //将表体数字转化为字符串
	outtextxy(5, y, name.c_str());
	outtextxy(105, y, gender.c_str());      //输出表
	outtextxy(190, y, tablebody.c_str());
	y += 30;
	if (y == (m+2)*30)
	{                        //m是目前表中学生数(Stu.size()),该循环使每次输出表后y值重归于30,下次还在原位置输出表
		y = 30;                 
	}
}


4.Management类成员函数的定义(逐个说明)

(1)文件写入函数

应用了二进制文件的写入操作,包含在文件

#include<fstream>

中,把数据读入到文档中的文本文件,其他成员函数操作后都要调用文件写入函数来实现存档  的功能。

//写入文件数据函数
void Management::writeData(const string& fileName)
{
	fstream write(fileName.c_str(), ios::out);
	if (!write.is_open())
	{
		cerr << " file open failed" << endl;    //异常处理
		return;
	}
	TableHeader += '\n';
	write.write(TableHeader.c_str(), TableHeader.size());   //写入文件
	for (size_t i=0;i<Stu.size();i++)
	{
		string inf = Stu[i].f();                    
		write.write(inf.c_str(), inf.size());
	}
	write.close();
}

(2)文件读取函数

采用了二进制文件的读取操作,其中应用了getline读取字符串空格的功能,采用了C语言的memset创建初始值为0的数组,采用了stringstream流把整型数转换为字符数组,将文本文件中的信息读取。

//读取文件数据函数
void Management::readData(const string& fileName,char a[])
{
	fstream read(fileName.c_str(), ios::in);   //创建输入流对象
	if (!read.is_open())
	{
		cerr << " file open failed" << endl;    //异常处理
		return;
	}
	//读取表头
	read.getline(buf, 1024);    //读汉字
	TableHeader = buf;
	//读取数据
	while (!read.eof())
	{
		memset(a, 0, sizeof(a));
		read.getline(a, 1024);
		if (strlen(a) == 0)
			break;
		stringstream ss(a);     //数字变为字符数组,包含在头文件#include<sstream>中
		ss >>stu.name>>stu.gender>>stu.Class >> stu.StuNum >> stu.math >> stu.English >> stu.program;
        tablebody =ss.str();
		Stu.push_back(stu);   //将信息存入动态数组
	}
	read.close();      //关闭
}

(3)显示全部信息函数

先将存入数组的信息都转化为字符数组,然后应用EasyX图形库的outtextxy函数将学生信息输出到图形界面。

//显示全部数据函数
void Management::displayall()
{
	loadimage(NULL, "white.jpg", 700, 700);
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	settextstyle(20, 0, _T("楷体"), 0, 0, 5, false, false, false);
	outtextxy(5, 10,buf);
	for (auto&i:Stu)
	{   
		i.display(Stu.size()-1);	//传入数组中学生个数-1,因为display()中为m+2,此处传入 
    Stu.size()-1
	}
}

(4)添加学生信息函数

应用了InputBox弹出输入窗口,将所要添加学生的全部信息输入到一个字符数组中,然后写入文本文件。

//添加学生信息函数 
void Management::add()
{
	char stud[100];
	InputBox(stud, 100, "请依次输入姓名,性别,班级,学号,数学成绩,英语成绩,程序设计成绩:");
	fstream output("Grade.txt", ios::out | ios::ate|ios::app);  //接着文件尾写入
	output.write(stud, 30);
	output << '\n';
	output.close();
}

(5)查找学生信息函数

遍历数组中学生姓名,若与输入姓名相同,则输出该学生所有信息,若不同,则显示未查找到该学生信息。

//查找学生信息函数
void Management::find()
{
	char aim[30];
	InputBox(aim, 7, "请输入要查找学生的姓名:");
	loadimage(NULL, "white.jpg", 700, 700);
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	settextstyle(20, 0, _T("楷体"), 0, 0, 5, false, false, false);
	int ap = 1;                       //标记量
	for (size_t j=0;j<Stu.size();j++)
	{
		if (Stu[j].name == aim)
		{   
			outtextxy(5, 10, buf);      //查找成功后将该生信息展示
			Stu[j].display(0);
			ap = 2;
			break;
		}
		else if(j == Stu.size() - 1 && ap == 1)
		{
			outtextxy(250, 300, "未查找到此人信息");
			break;
		}
	}
}

(6)删除学生信息函数

输入想删除的学生的姓名,进行查找,若找到该学生,调用Vector的函数erase(),将该学生信息删除,若未查找到该学生的名字,则显示未查找到该学生信息。

//删除学生信息函数
void Management::Erase()
{
	int po = 1;
	char dis[30];
	InputBox(dis, 7, "请输入要删除学生的姓名");
	loadimage(NULL, "white.jpg", 700, 700);
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	settextstyle(20, 0, _T("楷体"), 0, 0, 5, false, false, false);
	for (size_t k=0;k<Stu.size();k++)
	{
		
		if (Stu[k].name==dis)
		{
			po = 2;
			Stu.erase(Stu.begin()+k,Stu.begin()+k+1);     //查找成功,从vector中删除该值
			displayall();
			writeData("Grade.txt");
			break;
		}
		else if(k==Stu.size()-1&&po==1)
		{
			outtextxy(100, 200, "未找到此人信息");
		}
	}
}

(7)修改学生信息函数

同理,先输入要修改信息的学生姓名,再进行查找,如果查找成功,在该学生各项信息下面都有修改按钮,点击修改按钮,输入修改后的信息,退回封面,自动保存。

//修改学生信息函数
void Management::modify()
{
	int flag = 1;
	char old[30];
	char New[50];
	InputBox(old, 7, "请输入要修改学生的姓名:");
	loadimage(NULL, "white.jpg", 700, 700);
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	settextstyle(20, 0, _T("楷体"), 0, 0, 5, false, false, false);
	setfillcolor(LIGHTGRAY);
	for (size_t i = 0; i < Stu.size(); i++)
	{
		if (Stu[i].name == old)
		{
			outtextxy(5, 10, buf);
			Stu[i].display(0);
			fillrectangle(0, 60, 60, 90);
			fillrectangle(80, 60, 140, 90);
			fillrectangle(160, 60, 220, 90);
			fillrectangle(260, 60, 320, 90);
			fillrectangle(360, 60, 410, 90);
			fillrectangle(430, 60, 480, 90);
			fillrectangle(520, 60, 570, 90);
			fillrectangle(200, 300, 500, 350);
			outtextxy(10, 65, "修改");
			outtextxy(90, 65, "修改");
			outtextxy(170, 65, "修改");
			outtextxy(270, 65, "修改");
			outtextxy(365, 65, "修改");
			outtextxy(435, 65, "修改");
			outtextxy(525, 65, "修改");
			outtextxy(255, 315, "按两次Esc键返回封面");
			ExMessage Ms;
			int op = 1;
			do
			{
				flag = 2;
				Ms = getmessage(EM_MOUSE|EM_KEY);
				switch (Ms.message)
				{
				case WM_LBUTTONDOWN:
					if (Ms.x > 0 && Ms.x < 60 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的姓名:");
						Stu[i].name = New;
						break;
					}
					if (Ms.x > 80 && Ms.x < 140 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的性别:");
						Stu[i].gender = New;
						break;
					}
					if (Ms.x > 160 && Ms.x < 220 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的班级:");
						Stu[i].Class = atoi(New);
						break;
					}
					if (Ms.x > 260 && Ms.x < 320 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的学号:");
						Stu[i].StuNum = atoi(New);          //atoi()定义在#include<cstdlib>文件内,可将字符数组转化为int
						break;
					}
					if (Ms.x > 360 && Ms.x < 410 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的数学成绩:");
						Stu[i].math = atoi(New);             
						break;
					}
					if (Ms.x > 430 && Ms.x < 480 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的英语成绩:");
						Stu[i].English = atoi(New);
						break;
					}
					if (Ms.x > 520 && Ms.x < 570 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的程序设计成绩:");
						Stu[i].program = atoi(New);
						break;
					}
				case WM_KEYDOWN:
					if (Ms.vkcode = VK_ESCAPE)     //按Esc键返回封面
					{
						op = 0;
						break;
					}
				}
				if (op == 0)   break;     //跳出while循环
				
			} while (1);
		}
		 if (i == (Stu.size()-1) && flag == 1)
		{
			outtextxy(250, 300, "未查找到该学生信息");
			fillrectangle(200, 400, 500, 450);
			outtextxy(255, 415, "按两次Esc键返回封面");
			break;
		}
	}
	writeData("Grade.txt");          //保存修改数据
}

(8)成绩排序函数

因为动态数组中存储的都是类,所以要预先定义好比较的变量,

这里定义了一个小函数cmp,形式是两个对象的成绩总和进行比较,然后再调用STL容器中的sort()函数

,进行对成绩总和的排序。

bool cmp(student a, student b)      //定义排序方式
{
	return a.math+a.English+a.program > b.math+b.English+b.program;
}

//成绩排序函数
void Management::Sort()
{   
	sort(Stu.begin(), Stu.end(),cmp);      //sort()函数,排序成绩
	displayall();
}


6.Management类外定义成员函数(总)

#include "Management.h"
#include<graphics.h>
#include<conio.h>
#include<iostream>
#include<fstream>
#include<sstream>
#include<algorithm>
#include<string>
#include<vector>
#include<cstdlib>
using namespace std;

char buf[1024] = { 0 };
char a[1024] = { 0 };
string tablebody=" ";
string aimname;
student stu;         //创建一个学生对象
//构造函数读数据
Management::Management()
{
	readData("Grade.txt",a);
	//writeData("./test.txt");
}
//读取文件数据函数
void Management::readData(const string& fileName,char a[])
{
	fstream read(fileName.c_str(), ios::in);   //创建输入流对象
	if (!read.is_open())
	{
		cerr << " file open failed" << endl;    //异常处理
		return;
	}
	//读取表头
	read.getline(buf, 1024);    //读汉字
	TableHeader = buf;
	//读取数据
	while (!read.eof())
	{
		memset(a, 0, sizeof(a));
		read.getline(a, 1024);
		if (strlen(a) == 0)
			break;
		stringstream ss(a);     //数字变为字符数组,包含在头文件#include<sstream>中
		ss >>stu.name>>stu.gender>>stu.Class >> stu.StuNum >> stu.math >> stu.English >> stu.program;
        tablebody =ss.str();
		Stu.push_back(stu);   //将信息存入动态数组
	}
	read.close();      //关闭
}

//写入文件数据函数
void Management::writeData(const string& fileName)
{
	fstream write(fileName.c_str(), ios::out);
	if (!write.is_open())
	{
		cerr << " file open failed" << endl;    //异常处理
		return;
	}
	TableHeader += '\n';
	write.write(TableHeader.c_str(), TableHeader.size());   //写入文件
	for (size_t i=0;i<Stu.size();i++)
	{
		string inf = Stu[i].f();                    
		write.write(inf.c_str(), inf.size());
	}
	write.close();
}
//显示全部数据函数
void Management::displayall()
{
	loadimage(NULL, "white.jpg", 700, 700);
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	settextstyle(20, 0, _T("楷体"), 0, 0, 5, false, false, false);
	outtextxy(5, 10,buf);
	for (auto&i:Stu)
	{   
		i.display(Stu.size()-1);	//传入数组中学生个数-1,因为display()中为m+2,此处传入Stu.size()-1
	}
}

//添加学生信息函数 
void Management::add()
{
	char stud[100];
	InputBox(stud, 100, "请依次输入姓名,性别,班级,学号,数学成绩,英语成绩,程序设计成绩:");
	fstream output("Grade.txt", ios::out | ios::ate|ios::app);  //接着文件尾写入
	output.write(stud, 30);
	output << '\n';
	output.close();
}

//查找学生信息函数
void Management::find()
{
	char aim[30];
	InputBox(aim, 7, "请输入要查找学生的姓名:");
	loadimage(NULL, "white.jpg", 700, 700);
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	settextstyle(20, 0, _T("楷体"), 0, 0, 5, false, false, false);
	int ap = 1;                       //标记量
	for (size_t j=0;j<Stu.size();j++)
	{
		if (Stu[j].name == aim)
		{   
			outtextxy(5, 10, buf);      //查找成功后将该生信息展示
			Stu[j].display(0);
			ap = 2;
			break;
		}
		else if(j == Stu.size() - 1 && ap == 1)
		{
			outtextxy(250, 300, "未查找到此人信息");
			break;
		}
	}
}

//删除学生信息函数
void Management::Erase()
{
	int po = 1;
	char dis[30];
	InputBox(dis, 7, "请输入要删除学生的姓名");
	loadimage(NULL, "white.jpg", 700, 700);
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	settextstyle(20, 0, _T("楷体"), 0, 0, 5, false, false, false);
	for (size_t k=0;k<Stu.size();k++)
	{
		
		if (Stu[k].name==dis)
		{
			po = 2;
			Stu.erase(Stu.begin()+k,Stu.begin()+k+1);     //查找成功,从vector中删除该值
			displayall();
			writeData("Grade.txt");
			break;
		}
		else if(k==Stu.size()-1&&po==1)
		{
			outtextxy(100, 200, "未找到此人信息");
		}
	}
}


//修改学生信息函数
void Management::modify()
{
	int flag = 1;
	char old[30];
	char New[50];
	InputBox(old, 7, "请输入要修改学生的姓名:");
	loadimage(NULL, "white.jpg", 700, 700);
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	settextstyle(20, 0, _T("楷体"), 0, 0, 5, false, false, false);
	setfillcolor(LIGHTGRAY);
	for (size_t i = 0; i < Stu.size(); i++)
	{
		if (Stu[i].name == old)
		{
			outtextxy(5, 10, buf);
			Stu[i].display(0);
			fillrectangle(0, 60, 60, 90);
			fillrectangle(80, 60, 140, 90);
			fillrectangle(160, 60, 220, 90);
			fillrectangle(260, 60, 320, 90);
			fillrectangle(360, 60, 410, 90);
			fillrectangle(430, 60, 480, 90);
			fillrectangle(520, 60, 570, 90);
			fillrectangle(200, 300, 500, 350);
			outtextxy(10, 65, "修改");
			outtextxy(90, 65, "修改");
			outtextxy(170, 65, "修改");
			outtextxy(270, 65, "修改");
			outtextxy(365, 65, "修改");
			outtextxy(435, 65, "修改");
			outtextxy(525, 65, "修改");
			outtextxy(255, 315, "按两次Esc键返回封面");
			ExMessage Ms;
			int op = 1;
			do
			{
				flag = 2;
				Ms = getmessage(EM_MOUSE|EM_KEY);
				switch (Ms.message)
				{
				case WM_LBUTTONDOWN:
					if (Ms.x > 0 && Ms.x < 60 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的姓名:");
						Stu[i].name = New;
						break;
					}
					if (Ms.x > 80 && Ms.x < 140 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的性别:");
						Stu[i].gender = New;
						break;
					}
					if (Ms.x > 160 && Ms.x < 220 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的班级:");
						Stu[i].Class = atoi(New);
						break;
					}
					if (Ms.x > 260 && Ms.x < 320 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的学号:");
						Stu[i].StuNum = atoi(New);          //atoi()定义在#include<cstdlib>文件内,可将字符数组转化为int
						break;
					}
					if (Ms.x > 360 && Ms.x < 410 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的数学成绩:");
						Stu[i].math = atoi(New);             
						break;
					}
					if (Ms.x > 430 && Ms.x < 480 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的英语成绩:");
						Stu[i].English = atoi(New);
						break;
					}
					if (Ms.x > 520 && Ms.x < 570 && Ms.y>60 && Ms.y < 90)
					{
						InputBox(New, 10, "请输入修改后的程序设计成绩:");
						Stu[i].program = atoi(New);
						break;
					}
				case WM_KEYDOWN:
					if (Ms.vkcode = VK_ESCAPE)     //按Esc键返回封面
					{
						op = 0;
						break;
					}
				}
				if (op == 0)   break;     //跳出while循环
				
			} while (1);
		}
		 if (i == (Stu.size()-1) && flag == 1)
		{
			outtextxy(250, 300, "未查找到该学生信息");
			fillrectangle(200, 400, 500, 450);
			outtextxy(255, 415, "按两次Esc键返回封面");
			break;
		}
	}
	writeData("Grade.txt");          //保存修改数据
}

bool cmp(student a, student b)      //定义排序方式
{
	return a.math+a.English+a.program > b.math+b.English+b.program;
}

//成绩排序函数
void Management::Sort()
{   
	sort(Stu.begin(), Stu.end(),cmp);      //sort()函数,排序成绩
	displayall();
}


7.主函数

#include"Management.h"
#include<graphics.h>
#include<iostream>
#include<fstream>
#include<conio.h>
using namespace std;
void init();        //函数声明,封面设计函数
void Button();      //函数声明,按钮触发函数
int main()
{
	initgraph(700, 700);   //设置窗口大小
	init();
	while (1)
	{
		Button();     
	}
    _getch();      //阻塞函数,防止窗口闪退
	closegraph();
	return 0;
}
void init()
{
	loadimage(NULL, "./cover.jpg",700,700);     //加载封面图片
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);                       //设置字体颜色
	settextstyle(60, 0, _T("楷体"), 0, 0, 5, false, false, false);
	outtextxy(110, 80, "学生成绩管理系统");
	setfillcolor(RED);
	fillrectangle(250, 180, 440, 230);
	fillrectangle(250, 230, 440, 280);
	fillrectangle(250, 280, 440, 330);
	fillrectangle(250, 330, 440, 380);           //设计七个按钮
	fillrectangle(250, 380, 440, 430);
	fillrectangle(250, 430, 440, 480);
	fillrectangle(250, 480, 440, 530);
	settextstyle(30, 0, _T("宋体"), 0, 0, 5, false, false, false);
	outtextxy(285, 190, "查看全部");
	outtextxy(285, 240, "添加学生");
	outtextxy(285, 290, "删除学生");
	outtextxy(285, 340, "查找学生");
	outtextxy(285, 390, "修改学生");
	outtextxy(285, 440, "成绩排序");
	outtextxy(285, 490, "退出系统");
	settextstyle(20, 0, _T("楷体"), 0, 0, 50, false, false, false);
	outtextxy(580, 105, "(1.0)");
}
void Button()
{
	ExMessage msg;
	Management m;                        //定义一个Management对象
	msg = getmessage(EM_MOUSE|EM_KEY);        //鼠标交互和键盘交互
	switch (msg.message)                   
	{
	case WM_LBUTTONDOWN:
		if (msg.x > 250 && msg.x < 440 && msg.y>180 && msg.y < 230)
		{
			m.displayall();
			break;
		}
		if (msg.x > 250 && msg.x < 440 && msg.y>230 && msg.y < 280)
		{
			m.add();
			break;
		}
		if (msg.x > 250 && msg.x < 440 && msg.y>280 && msg.y < 330)
		{
			m.Erase();
			break;
		}
		if (msg.x > 250 && msg.x < 440 && msg.y>330 && msg.y < 380)
		{
			m.find();
			break;
		}
		if (msg.x > 250 && msg.x < 440 && msg.y>380 && msg.y < 430)
		{
			m.modify();
			break;
		}
		if (msg.x > 250 && msg.x < 440 && msg.y>430 && msg.y < 480)
		{
			m.Sort();
			break;
		}
		if (msg.x > 250 && msg.x < 440 && msg.y>480 && msg.y < 530)
		{
			m.writeData("Grade.txt");            //保存并退出
			exit(0);
			break;
		}
	case WM_KEYDOWN:
		if (msg.vkcode = VK_ESCAPE)     //按Esc键返回封面
		{
			init();
			break;
		}
	}
}

鸣谢:参考了b站up主C语言Plus的课



版权声明:本文为qq_53162179原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。