//“linklist.h”
#pragma once //防止头文件重复包含
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<conio.h>
#include<Windows.h>
#include<string.h>
#include<graphics.h> //图形库头文件
#include<mmsystem.h> //音乐播放头文件
#pragma comment( lib,"winmm.lib" ) //静态库
// 学生信息定义为结构体作为,且作为单链表的数据域
struct Score //成绩
{
double Chinese, Math, English, Major, C, Cadd, Datastruct, History, Physics, Politics;
};
struct student //学生基本信息
{
char name[20]; //姓名
char birthday[20]; //出生日期
char sex[10]; //性别
char num[20]; //学号
char major[30]; //系别
char classes[20]; //班级
char nativePlace[70]; //籍贯
char date[20]; //入学日期
struct Score score;
};
typedef struct node
{
struct student data; //数据域
struct node* next; //指针域
}Node, *pNode;
IMAGE bkImage, menuImage; //图形变量
//创建表
pNode createList()
{
pNode list = (pNode)malloc(sizeof(Node));
if (NULL == list) //防御措施,预防不成功的情况
{
return 0;
}
list->next = NULL; //指向空,NULL作为链表结尾的标志
return list;
}
//创建结点
pNode creatNode(struct student data) //传入数据加到结点中
{
pNode node = (pNode)malloc(sizeof(Node)); //malloc开辟堆内存,返回的是(void*),所以需要强转
node->data = data;
node->next = NULL; //重置新的链表尾部为NULL
return node;
}
/*--------------创建链表,存储数据信息-------------*/
pNode list = createList(); //头结点
/*
//插入结点:采用尾插法
void insertNodeByTail(pNode list, struct student data)
{
pNode newNode = creatNode(data); //调用创建结点的函数
pNode p = list;
while (NULL != p->next)
{
p = p->next;
}
newNode->next = NULL;
p->next = newNode;
}
*/
void insertNodeByTail(pNode list, struct student data)
{
pNode newNode = creatNode(data); //调用创建结点的函数
pNode p = list;
while (NULL != p->next)
{
p = p->next;
}
newNode->next = NULL;
p->next = newNode;
}
/*------------------学生管理系统的录入信息-------------*/
void addstudentInfo(pNode list) //录入信息
{
struct student data;
FILE *fp = fopen("学生信息.xlsx", "r");
fseek(fp, 8L, SEEK_SET); // 从文件第二行开始读取
while (!feof(fp)) //表示未到文件末尾
{
fscanf(fp, "%s%s%s%s%s%s%s%s", data.name, data.birthday, data.sex, data.num, data.major, data.classes, data.nativePlace, data.date);
/*printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", data.name, data.birthday, data.sex, data.num, data.major, data.classes, data.nativePlace, data.date);*/
insertNodeByTail(list, data);
}
fclose(fp);
}
//查找信息:通过num查找
pNode searchNodeByNum(pNode list, char* searchNum)
{
pNode p = list; //定义一个临时结点,不能用头结点直接操作,容易乱
pNode pNext = p->next;
while (NULL != pNext&&strcmp(pNext->data.num, searchNum))
{ //通过遍历,比较链表中的num和要查找的num
p = pNext;
pNext = p->next;
}
if (NULL != pNext) //判断是否找到了
{
return pNext;
}
else //没找到
{
return NULL;
}
}
/*----------------通过num查找信息------------*/
void searchInfoByNum() //查找信息
{
putimage(0, 0, &bkImage); //重贴背景图
setlinecolor(RGB(249, 9, 20));
//for (int i = 0; i < 2; i++) //画表格
//{
// rectangle(50, 50 + i * 35, 150, 85 + i * 35);
//}
char searchNum[20] = "";
outtextxy(100, 52, "请输入要查找的学号:");
int i = 0;
int ch;
int startX = 500;
while (13 != (ch = _getch()))//不等于换行符
{
outtextxy(startX, 52, ch);
startX += 13; //第二个字符不能覆盖第一个
searchNum[i++] = ch;
}
//字符到字符串的处理 注意'\0'
searchNum[i] = '\0';
if (NULL == searchNodeByNum(list, searchNum)) //没有信息
{
outtextxy(100, 88, "暂无信息,请添加");
setcolor(RGB(249, 9, 20));
outtextxy(130, 130, "请按下Enter键后回到主菜单"); //按下Enter键后结束
while (13 != (ch = _getch()))
;
return;
}
else //有信息时输出
{
printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", searchNodeByNum(list, searchNum)->data.name, searchNodeByNum(list, searchNum)->data.birthday, searchNodeByNum(list, searchNum)->data.sex, searchNodeByNum(list, searchNum)->data.num, searchNodeByNum(list, searchNum)->data.sex, searchNodeByNum(list, searchNum)->data.classes, searchNodeByNum(list, searchNum)->data.nativePlace, searchNodeByNum(list, searchNum)->data.date);
outtextxy(100, 88, "姓名:");
outtextxy(170, 88, searchNodeByNum(list, searchNum)->data.name);
outtextxy(260, 88, "出生日期:");
outtextxy(330, 88, searchNodeByNum(list, searchNum)->data.birthday);
outtextxy(388, 88, "性别:");
outtextxy(460, 88, searchNodeByNum(list, searchNum)->data.sex);
outtextxy(550, 88, "学号:");
outtextxy(600, 88, searchNodeByNum(list, searchNum)->data.num);
outtextxy(100, 120, "系别:");
outtextxy(170, 120, searchNodeByNum(list, searchNum)->data.sex);
outtextxy(260, 120, "班级:");
outtextxy(330, 120, searchNodeByNum(list, searchNum)->data.classes);
outtextxy(388, 120, "籍贯:");
outtextxy(460, 120, searchNodeByNum(list, searchNum)->data.nativePlace);
outtextxy(550, 120, "入学日期:");
outtextxy(600, 120, searchNodeByNum(list, searchNum)->data.date);
//按下Enter键后返回主菜单
setcolor(RGB(249, 9, 20));
outtextxy(170, 130, "按下Enter键后回到主菜单");
while (13 != (ch = _getch()))
;
return;
}
}
//删除结点:通过num删除结点
int deleteNodeByNum(pNode list, char* searchNum)
{
pNode p = list; //临时结点,便于遍历
pNode pNext = p->next; //临时结点
while (NULL != pNext&&strcmp(pNext->data.num, searchNum))
{ //通过遍历,比较链表中的num和要查找的num
p = pNext;
pNext = p->next;
}
if (NULL == pNext) //判断是否找到
{
return 0; //返回删除失败
}
else
{
p->next = pNext->next; //跨越要删除的结点
free(pNext); //删除结点
return 1; //删除成功
}
}
//删除
void deleteInfoByNum()
{
//struct Student data; //先查找,再删除,197~239行,为寻找过程,代码和查找一样
putimage(0, 0, &bkImage); //重贴背景图
for (int i = 0; i < 2; i++) //画表格
{
setlinecolor(RGB(249, 9, 20));
rectangle(100, 50 + i * 35, 500, 85 + i * 35);
}
char searchNum[20];
outtextxy(100, 52, "请输入要查找的学号:");
int i = 0;
int ch;
int startX = 400;
while (13 != (ch = _getch()))//不等于换行符
{
outtextxy(startX, 52, ch);
startX += 13; //第二个字符不能覆盖第一个
searchNum[i++] = ch;
}
//字符到字符串的处理 注意'\0'
searchNum[i] = '\0';
if (NULL == searchNodeByNum(list, searchNum)) //没有信息
{
setcolor(RGB(249, 9, 20));
outtextxy(100, 88, "暂无信息");
outtextxy(130, 130, "请按下Enter键后回到主菜单"); //按下Enter键后结束
while (13 != (ch = _getch()))
;
return;
}
else
{
outtextxy(100, 88, "姓名:");
outtextxy(170, 88, searchNodeByNum(list, searchNum)->data.name);
outtextxy(260, 88, "出生日期:");
outtextxy(330, 88, searchNodeByNum(list, searchNum)->data.birthday);
outtextxy(388, 88, "性别:");
outtextxy(460, 88, searchNodeByNum(list, searchNum)->data.sex);
outtextxy(550, 88, "学号:");
outtextxy(600, 88, searchNodeByNum(list, searchNum)->data.num);
outtextxy(100, 120, "系别:");
outtextxy(170, 120, searchNodeByNum(list, searchNum)->data.sex);
outtextxy(260, 120, "班级:");
outtextxy(330, 120, searchNodeByNum(list, searchNum)->data.classes);
outtextxy(388, 120, "籍贯:");
outtextxy(460, 120, searchNodeByNum(list, searchNum)->data.nativePlace);
outtextxy(550, 120, "入学日期:");
outtextxy(600, 120, searchNodeByNum(list, searchNum)->data.date);
//按下Enter键后返回主菜单
setcolor(RGB(249, 9, 20));
outtextxy(130, 130, "按下Enter键后回到主菜单");
while (13 != (ch = _getch()))
;
deleteNodeByNum(list, searchNum);
return;
}
}
//打印结点信息
void printStudentInfo(pNode list)
{
int ch; //接住键盘消息
putimage(0, 0, &bkImage);
if (NULL == list->next)
{
settextcolor(RGB(249, 9, 20));
outtextxy(100, 88, "暂无信息,请添加");
//按下Enter键后返回主菜单
outtextxy(130, 130, "请按下Enter键后回到上级菜单");
while (13 != (ch = _getch()))
;
return;
}
else
{
fillrectangle(100, 50, 500, 330);
for (int i = 0; i < 8; i++) //画表格
{
setlinecolor(RGB(249, 9, 20));
rectangle(100, 50 + i * 35, 500, 85 + i * 35);
}
line(233, 50, 233, 330);
line(367, 50, 367, 330);
setcolor(RGB(249, 9, 20));
outtextxy(137, 53, "姓名");
outtextxy(273, 53, "学号");
outtextxy(400, 53, "等分");
int lineWidth = 0; //行高
pNode p = list->next;
setcolor(RGB(0, 104, 208));
while (p) //!=NULL
{ //打印消息
outtextxy(120, 90 + lineWidth, p->data.name);
outtextxy(238, 90 + lineWidth, p->data.num);
outtextxy(410, 90 + lineWidth, p->data.classes);
p = p->next;
lineWidth += 35; //满了,换行
}
setcolor(RGB(249, 9, 20));
outtextxy(130, 350, "按下Enter键后回到主菜单"); //按下Enter键后返回主菜单
while (13 != (ch = _getch()))
;
return;
}
}
/*----------------------窗口界面---------------------
贴图:
定义图片变量:IMAGE img;
加载图片:loadimage(&img,"图片的地址");
贴图:putimage(int x,int y,&img);//图片的长,宽,地址
*/
void studentSystemwindow() //窗口界面
{
loadimage(&bkImage, "bk.jpg", 900, 600); //加载图片
loadimage(&menuImage, "menubk.jpg", 300, 75);
BeginBatchDraw(); //开始批量绘制 不显示
//mciSendString("open 小情歌.mp3 alias bgm", NULL, NULL, NULL); //加载音乐
//mciSendString("play bgm repeat", NULL, NULL, NULL); //循环播放音乐
//贴图
putimage(0, 0, &bkImage);
for (int i = 0; i < 4; i++)
{
putimage(300, 150 + 110 * i, &menuImage);
}
setcolor(RGB(249, 9, 20)); //用RGB设置颜色
setbkmode(TRANSPARENT); // 设置背景混合模式,1默认为TRANSPARENT
settextstyle(50, 0, "新宋体"); // 设置当前字体样式,高30,宽0为自适应,字体为新宋体
/*----------------------菜单内容--------------------*/
outtextxy(100, 45, "北华大学学生综合测评管理系统");
setcolor(RGB(0, 104, 208));
settextstyle(40, 0, "新宋体"); // 设置当前字体样式,高30,宽0为自适应,字体为新宋体
outtextxy(380, 170, "学生信息");
outtextxy(420, 170 + 110 * 1, "成绩");
outtextxy(400, 170 + 110 * 2, "创新分");
outtextxy(380, 170 + 110 * 3, "活动奖惩");
EndBatchDraw(); //结束绘制 把前面所有内容显示出来
}
void is_exit(pNode list) //判断退出
{
if (IDYES == MessageBox(NULL, "你确定退出吗?", "请按下按钮 ", MB_YESNO))
{
pNode p = list; //定义两个临时结构体指针,便于释放结点内存,
pNode q = list; //而且让它们都指向第一个节点
while (p != NULL)
{
p = p->next;
free(q);//释放节点
q = p;//移动q 开始下一轮循环
}
list = NULL; //良好的习惯,虽然没什么卵用
setbkcolor(WHITE); //设置背景颜色为白色
cleardevice(); //刷新屏幕
setcolor(RGB(249, 9, 20));
outtextxy(150, 150, "已保存,正在退出......");
Sleep(2000);
exit(0); //直接结束程序
}
else
return;
}
/*
模块一: 成绩管理
1)各学科成绩管理:
学生可以通过本模块查看其各个学科的成绩。
2) 活动加分管理
本模块是学生查询其参加各个活动所加的活动分记录。学生可以通过填写加分异常对自己的加分情况提出异议。
3) 体育分管理:
本模块是学生查询其体育所得的分的记录
4)综测分管理
本模块是通过对各学科分数,活动加分,体育分按一定换算公式获得的综测成绩。
综测成绩换算公式为:活动乘20% 学习75% 体育5 %= 综测成绩
*/
void init()
{
MOUSEMSG m; //鼠标变量,用于获取鼠标信息
while (true)
{
m = GetMouseMsg(); //获得鼠标消息
switch (m.uMsg)
{
case WM_LBUTTONDOWN: //鼠标左键按下
if (m.x > 300 && m.x<600 && m.y>150 && m.y < 225)//各学科成绩
{
BeginBatchDraw(); //开始批量绘制 不显示
putimage(0, 0, &bkImage);
for (int i = 0; i < 4; i++)
{
putimage(300, 150 + 110 * i, &menuImage);
}
setcolor(RGB(249, 9, 20)); //用RGB设置颜色
setbkmode(TRANSPARENT); // 设置背景混合模式,1默认为TRANSPARENT
settextstyle(50, 0, "新宋体"); // 设置当前字体样式,高30,宽0为自适应,字体为新宋体
/*----------------------成绩管理模块菜单内容--------------------*/
setcolor(RGB(0, 104, 208));
settextstyle(40, 0, "新宋体"); // 设置当前字体样式,高30,宽0为自适应,字体为新宋体
outtextxy(380, 170, "按学号查找成绩");
outtextxy(420, 170 + 110 * 1, "按姓名查找成绩");
outtextxy(400, 170 + 110 * 2, "按班级浏览");
outtextxy(380, 170 + 110 * 3, "退出");
EndBatchDraw(); //结束绘制 把前面所有内容显示出来
}
break;
if (m.x > 300 && m.x<600 && m.y>260 && m.y < 335)//活动加分
break;
if (m.x > 300 && m.x<600 && m.y>370 && m.y < 445)//体育分
break;
if (m.x > 300 && m.x<600 && m.y>480 && m.y < 555)//综测分
break;
default:
break;
}
}
}
void initview()
{
BeginBatchDraw(); //开始批量绘制 不显示
putimage(0, 0, &bkImage);
for (int i = 0; i < 4; i++)
{
putimage(300, 150 + 110 * i, &menuImage);
}
setcolor(RGB(249, 9, 20)); //用RGB设置颜色
setbkmode(TRANSPARENT); // 设置背景混合模式,1默认为TRANSPARENT
settextstyle(50, 0, "新宋体"); // 设置当前字体样式,高30,宽0为自适应,字体为新宋体
/*----------------------成绩管理模块菜单内容--------------------*/
outtextxy(100, 45, "学生成绩管理模块");
setcolor(RGB(0, 104, 208));
settextstyle(40, 0, "新宋体"); // 设置当前字体样式,高30,宽0为自适应,字体为新宋体
outtextxy(380, 170, "各学科成绩");
outtextxy(420, 170 + 110 * 1, "活动加分");
outtextxy(400, 170 + 110 * 2, "体育分");
outtextxy(380, 170 + 110 * 3, "综测分");
EndBatchDraw(); //结束绘制 把前面所有内容显示出来
void init();
MOUSEMSG m;
while (true)
{
m = GetMouseMsg(); //获得鼠标消息
switch (m.uMsg)
{
case WM_LBUTTONDOWN: //鼠标左键按下
if (m.x > 300 && m.x<600 && m.y>150 && m.y < 225)//按学号查找
{
searchInfoByNum();
}
break;
if (m.x > 300 && m.x<600 && m.y>260 && m.y < 335)//活动加分
studentSystemwindow();
break;
if (m.x > 300 && m.x<600 && m.y>370 && m.y < 445)//体育分
rectangle(200, 500, 80, 60);
break;
if (m.x > 300 && m.x<600 && m.y>480 && m.y < 555)//综测分
is_exit(list);
break;
default: //其他情况
break;
}
}
}
void addStudentScoe(pNode list) //录入信息
{
struct student data;
putimage(0, 0, &bkImage); //重贴背景图
setlinecolor(RGB(249, 9, 20));
for (int i = 0; i < 2; i++) //画表格
{
rectangle(100, 50 + i * 35, 500, 85 + i * 35);
}
line(233, 50, 233, 120);
line(367, 50, 367, 120);
//长20,宽0表示自适应
settextstyle(20, 0, "新宋体");
outtextxy(140, 60, "语文");
outtextxy(273, 60, "数学");
outtextxy(406, 60, "英语");
outtextxy(140, 110, "C语言");
outtextxy(273, 110, "C++");
outtextxy(406, 110, "数据结构");
outtextxy(140, 160, "历史");
outtextxy(273, 160, "物理");
outtextxy(406, 160, "政治");
char arr[20];
sprintf(arr, "%lf", data.score.Chinese);
InputBox(arr, 20, "请输入语文成绩: ");//弹出框,用于输入
outtextxy(140, 90, data.score.Chinese);
sprintf(arr, "%lf", data.score.Math);
InputBox(arr, 20, "请输入数学成绩: ");
outtextxy(140, 90, data.score.Math);
sprintf(arr, "%lf", data.score.English);
InputBox(arr, 20, "请输入英语成绩: ");
outtextxy(140, 90, data.score.English);
sprintf(arr, "%lf", data.score.C);
InputBox(arr, 20, "请输入C语言成绩: ");
outtextxy(140, 90, data.score.C);
sprintf(arr, "%lf", data.score.Cadd);
InputBox(arr, 20, "请输入C++成绩: ");
outtextxy(140, 90, data.score.Cadd);
sprintf(arr, "%lf", data.score.Datastruct);
InputBox(arr, 20, "请输入数据结构: ");
outtextxy(140, 90, data.score.Datastruct);
sprintf(arr, "%lf", data.score.History);
InputBox(arr, 20, "请输入历史成绩: ");
outtextxy(140, 90, data.score.History);
sprintf(arr, "%lf", data.score.Physics);
InputBox(arr, 20, "请输入物理成绩: ");
outtextxy(140, 90, data.score.Physics);
sprintf(arr, "%lf", data.score.Politics);
InputBox(arr, 20, "请输入政治成绩: ");
outtextxy(140, 90, data.score.Politics);
insertNodeByTail(list, data); //把信息加入到链表
outtextxy(180, 130, "保存中,请稍后......");//给一个假象,加强用户体验
}
/*----------------------用户用鼠标操作-------------------------*
1.定义鼠标消息 MOUSEMSG m;
2.获取鼠标消息 m=GetMouseMsg();
3.判断鼠标消息的类型 WM_LBUTTONDOWN
*/
void userKeyDown()
{
MOUSEMSG m; //鼠标变量,用于获取鼠标信息
addstudentInfo(list);
while (true)
{
m = GetMouseMsg(); //获得鼠标消息
switch (m.uMsg)
{
case WM_LBUTTONDOWN: //鼠标左键按下
if (m.x > 300 && m.x<600 && m.y>150 && m.y < 225)//学生信息
{
initview();
searchInfoByNum();
studentSystemwindow();
}
break;
if (m.x > 300 && m.x<600 && m.y>260 && m.y < 335)//成绩
studentSystemwindow();
break;
if (m.x > 300 && m.x<600 && m.y>370 && m.y < 445)//创新分
rectangle(200, 500, 80, 60);
break;
if (m.x > 300 && m.x<600 && m.y>480 && m.y < 555)//活动奖罚
is_exit(list);
break;
default: //其他情况
break;
}
}
}