一,系统概括
- 该系统拥有存储学生信息和处理信息功能(增删改查)。
- 该系统基于C语言(c++)和easyx图形库。
- 字符集才用多字符节!!!!!!!!!!!!!
- 代码功能实现基于单链表操作。
- 附加功能:光标感应、输出显示信息时有上下分页、没用的进度条、清空链表。
二 ,设计思路
在c语言课程设计基础上加入easyx图形库,使可进行更深层次的人机交互。
结构:
死循环扫描按键(光标感应)->点击按键->执行按键功能->继续循环。
链表操作使用尾插法(为了数据排列整齐),头结点引导链表。链表功能操作包括插入、删除、修改、查找、清空。还有文件操作可对数据进行自动存读。
没用的进度条:
因敲代码的过程中灵光一现--做个进度条吧于是乎埋头苦干终于在五分钟后它诞生了。它是我的产物!哦,它是多么的伟大与没用! 这个是没用的。进度条是用easyx的画有填充矩形函数为基础做的一个动画。循环逐渐让矩形变长。
查看信息时的上下页操作:
1,下一页:
下一页比较好做;在遍历输出时进行微操,我窗口设计最多只能输出26个学生信息,所以在输出到第26个学生后停止输出并把指向第26信息的指针返回。在使用这个函数时用一个指针变量被赋给函数的返回指针。下次再执行时就可以在第26信息进行输出,以此类推第52,第78......
stu 是自定义数据类型,原数据类型为struct Student
stu* printlist(stu* list)//输出整个链表数据函数。参数表头指针
{ //参数链表
stu* temp;
unsigned int i;
i = 37;
float flag=0;
temp = list->next;
nodoLine();//表格绘制
while (temp)
{
outtextxy(13, i ,temp->date.name); outtextxy(249, i, temp->date.number); outtextxy(482, i, temp->date.point);//文字输出形式
i += 25;
flag++;
if((flag/26.0)>=1)//到26个停止输出
{
break;
}
else
{temp = temp->next; }
}
return temp;//返回位置指针
}
2,上一页(精华):
在下一页的基础上,对指针进行操作,让指针指到(上26+本页数据数)的位置然后返回“上一页开始”位置指针,再由以上“下一页函数”输出。这里有两种情况,
1,本页数据数没有满26,需要减去当前页的数据数.
2,本页数据数满26,需要减去当前页的数据数即26.
//stu 为自定义数据类型,原类型为struct Student
stu* lastprintlist(stu* list, stu* temp)//输出上一页数据函数,每26个学生数据为一页;
{ //参数链表和上次位置指针
stu* temp1 = temp;
stu* temp2 = list;
int flag = 0, zhongjian = 0;//flag 经处理后为当前位置指针指向的位数
//zhongjian 经处理后为“总数据数-当前页的数据数-26”
while (temp2 != temp1)
{
flag++;
temp2 = temp2->next;
}
if (flag <= 26)
{
return temp1;
}
else
{
temp2 = list;//重置位置
if (flag % 26 == 0)
{
zhongjian = flag - 2 * 26;
}
else
{
zhongjian = flag - (flag % 26 + 26);
}
while (zhongjian)
{
temp2 = temp2->next;
zhongjian--;
}
}
return temp2;//返回上一页开始位置指针
}
三,源代码
记得字符集换成多字符节!!!
记得字符集换成多字符节!!!
记得字符集换成多字符节!!!
重要的事情说三遍!
头文件Function.h
主要有链表操作函数以及文件操作
#include<easyx.h>
#include<stdio.h>
#include<string.h>
#include<Windows.h>
struct Date//定义学生信息结构体
{
char name[20];
char number[20];
char point[20];
};
struct Student //定义链表结构体
{
struct Date date;
struct Student* next;
};
typedef struct Student stu;
unsigned int count;
void nodoLine()//表格绘制
{
setlinecolor(BLACK);
setbkcolor(WHITE);
setlinestyle(PS_SOLID, 3);
clearcliprgn();
line(0, 2, 700, 2);
line(0, 6, 700, 6);
line(0, 30, 700, 30);
line(0, 34, 700, 34);
line(2, 0, 2, 700);
line(6, 0, 6, 700);
line(697,0,697,700);
line(693, 0, 693, 700);
line(0, 697, 700, 697);
line(0,693,700,693);
setlinestyle(PS_SOLID, 1);
line(240, 0, 240, 700);
line(473, 0, 473, 700);
for(int i=0;i<27;i++)
{
line(0,60+25*i,700, 60 + 25 * i);
}
settextcolor(RED);
outtextxy(10, 10, "姓名");
outtextxy(246, 10, "学号");
outtextxy(479, 10, "分数");
settextcolor(BLACK);
}
stu* creatheadlist()//创建表头的函数
{
stu* po = (stu*)malloc(sizeof(stu));
po->next = NULL;
return po;
};
stu* creatnode(struct Date date)//创建结点函数,参数数据结构体
{
stu* po = (stu*)malloc(sizeof(stu));
po->date = date;
po->next = NULL;
return po;
}
void setnode(stu* list, struct Date* date)//插入链表函数,参数表头指针、数据结构体指针
{ //使尾插法插入结点
stu* temp = creatnode(*date);
stu* p=list;
temp->date = *date;
temp->next =NULL;
while (p->next)
{
p = p->next;
}
p->next = temp;
}
stu* printlist(stu* list)//输出整个链表数据函数。参数表头指针
{
stu* temp;
unsigned int i;
i = 37;
float flag=0;
temp = list->next;
nodoLine();
while (temp)
{
outtextxy(13, i ,temp->date.name); outtextxy(249, i, temp->date.number); outtextxy(482, i, temp->date.point);//文字输出形式
i += 25;
flag++;
if((flag/26.0)>=1)
{
break;
}
else
{temp = temp->next; }
}
return temp;
}
//stu 为自定义数据类型,原类型为struct Student
stu* lastprintlist(stu* list, stu* temp)//输出上一页数据函数,每26个学生数据为一页;
{ //参数链表和上次位置指针
stu* temp1 = temp;
stu* temp2 = list;
int flag = 0, zhongjian = 0;//flag 经处理后为当前位置指针指向的位数
//zhongjian 经处理后为“总数据数-当前页的数据数-26”
while (temp2 != temp1)
{
flag++;
temp2 = temp2->next;
}
if (flag <= 26)
{
return temp1;
}
else
{
temp2 = list;//重置位置
if (flag % 26 == 0)
{
zhongjian = flag - 2 * 26;
}
else
{
zhongjian = flag - (flag % 26 + 26);
}
while (zhongjian)
{
temp2 = temp2->next;
zhongjian--;
}
}
return temp2;//返回上一页开始位置指针
}
void printnodo(stu* list)//输出单个结点函数,参数表头指针
{
stu* temp = list;
clearcliprgn();
settextstyle(25, 0, "黑体");
outtextxy(150, 50, "查找的学生信息");
graphdefaults();
outtextxy(10, 100, "姓名");
outtextxy(246, 100, "学号");
outtextxy(479, 100, "分数");
outtextxy(10, 150, temp->date.name); outtextxy(246, 150, temp->date.number); outtextxy(479, 150, temp->date.point);
}
struct Date* inputDate()//输入学生信息函数,输入完成返回数据结构体指针
{
struct Date *date=(struct Date*)malloc(sizeof(struct Date));
if (InputBox(date->name, 10, "请输入学生姓名", NULL, NULL, 0, 0, false))//判断按“取消”还是“确定键”,“取消”退出循环
{
if (InputBox(date->number, 10, "请输入学生学号", NULL, NULL, 0, 0, false))//判断按“取消”还是“确定键”,“取消”退出循环
{
if (InputBox(date->point, 10, "请输入学生分数", NULL, NULL, 0, 0, false))//判断按“取消”还是“确定键”,“取消”退出循环
{
return date;
}
else
{
return NULL;
}
}
else
{
return NULL;
}
}
else
return NULL;
}
void delnodo(char num[20],stu* list)//删除单个结点函数,参数删除学生的学号、表头指针。
{
stu* temp,*temp1;
temp1 = list;
temp = list->next;
if (temp == NULL)//if空链表退出
{
MessageBox(NULL, "无学生信息", "错误",0);
return;
}
while (temp)//遍历如果找到需要删除的学生信息,释放该内存并退出函数
{
if (strcmp(temp->date.number, num) == 0)
{
temp1->next = temp->next;
free(temp);
MessageBox(NULL, "成功删除学生信息", "妙啊", 0);
return;
}
temp1 = temp1->next;
temp = temp->next;
}MessageBox(NULL, "无学生信息", "错误", 0);//如果没有该学生,执行该句
}
void clearlist(stu* list)
{
stu* temp;
while (list->next)
{
temp = list->next;
list->next = temp->next;
free(temp);
}
temp = NULL;
}
stu* findDate(stu* list, char findDate[20])//查找指定学生信息函数,参数表头指针、指定学生学号,找到返回链表指针
{
stu* temp = list->next;
if(temp==NULL)//if空链表返回空
{
MessageBox(NULL, "无学生信息", "错误",MB_SYSTEMMODAL);
return NULL;
}
else
{
while (strcmp(temp->date.number, findDate)!=0)//指定学生信息跟链表内信息比较,不对一直循环,直到表尾;
{
temp = temp->next;
if (temp == NULL)
{
MessageBox(NULL, "无学生信息", "错误", MB_SYSTEMMODAL); return NULL;
}
}
}
if(strcmp(temp->date.number, findDate) == 0)//判断是否找到
{
MessageBox(NULL, "查找到了", "OK", MB_SYSTEMMODAL);
return temp;
}
else
{
MessageBox(NULL, "无学生信息", "错误", MB_SYSTEMMODAL); return NULL;
}
}
void writefile(char* filename, stu* listhead)//写入文件操作函数
{
FILE* fp; stu* list = listhead->next;
fp = fopen(filename, "w");
while (list)
{
fprintf(fp, "%s %s %s\n", list->date.name, list->date.number, list->date.point);
list = list->next;
}
fclose(fp);
}
void readfile(char* filename, stu* listhead)//读出文件操作函数
{
FILE* fp; fp = fopen(filename, "r");
struct Date temp;
if (fp == NULL)
{
fp = fopen(filename, "w+");
fclose(fp);
return;
}
while(fscanf(fp, "%s %s %s\n", temp.name, temp.number, temp.point)!=EOF)
{
setnode(listhead, &temp);
memset(&temp, 0, sizeof(temp));
}
fclose(fp);
}
主函数main.cpp
#include"Function.h"
/**
* 界面按键框宽度150,高度40,圆角宽9,圆角高9;用solidroundrect
*
*
*
*/
char filename[20] = "listDate.txt";
stu* list = creatheadlist();
void anniu(int x, int y, int xl, int yl, const char* i);
void showmeun();
void Dateprint();
void windowtextset(const char* text)//获取句柄并设置句柄函数
{
HWND kk = GetHWnd();
SetWindowText(kk, text);
}
void showanniuANDin()//界面按键功能以及按键动画函数
{
BeginBatchDraw();
ExMessage Mxy;
struct Date* temp = NULL; char delFlag[20], findFlag[20]; stu* findtemp = NULL;//一堆临时变量
if (peekmessage(&Mxy, EM_MOUSE))
{//判断“查看总信息”按键以及功能实现函数-----------------------------------------------------
if (Mxy.x >= 270 && Mxy.y <= 340 && Mxy.y >= 290 && Mxy.x <= 430)
{
clearrectangle(270, 290, 430, 340);
anniu(275, 295, 425, 335, "查看总信息");
if (Mxy.message == WM_LBUTTONDOWN)//鼠标点击判断
{
Dateprint();
showmeun();
FlushBatchDraw();
}
}
else {anniu(270, 290, 430, 340, "查看总信息");}
//------------------------------------------------------------------------------------------
//判断“添加学生信息”按键以及功能实现函数--------------------------------------------------
if (Mxy.x >= 270 && Mxy.y <= 400 && Mxy.y >= 350 && Mxy.x <= 430)
{
clearrectangle(270, 350, 430, 400);
anniu(275, 355, 425, 395, "添加学生信息");
if (Mxy.message == WM_LBUTTONDOWN)//鼠标点击判断
{
windowtextset("添加");
temp = inputDate();
if(temp==NULL)
{
return;
}
else
{
setnode(list, temp); writefile(filename, list);
}
}
}
else {anniu(270, 350, 430, 400, "添加学生信息"); }
//------------------------------------------------------------------------------------------
//判断“修改学生信息”按键以及功能实现函数--------------------------------------------------
if (Mxy.x >= 270 && Mxy.y <= 460 && Mxy.y >= 410 && Mxy.x <= 430)
{
clearrectangle(270, 410, 430, 460);
anniu(275, 415, 425, 455, "修改学生信息");
if (Mxy.message == WM_LBUTTONDOWN)//鼠标点击判断
{
windowtextset("修改");
temp = (struct Date*)malloc(sizeof(struct Date));
if(InputBox(findFlag, 10, "请输入需要查找学生学号", NULL, NULL, 0, 0, false))
{
findtemp = findDate(list, findFlag);
if (findtemp == NULL)
{
return;
}
else
{
printnodo(findtemp);
FlushBatchDraw();
InputBox(temp->name, 10, "请输入需要修改学生的姓名", NULL, NULL, 0, 0, false);
InputBox(temp->number, 10, "请输入需要修改学生的学号", NULL, NULL, 0, 0, false);
InputBox(temp->point, 10, "请输入需要修改学生的成绩", NULL, NULL, 0, 0, false);
findtemp->date= *temp;
MessageBox(NULL, "修改成功!!!", "OK", MB_SYSTEMMODAL);
writefile(filename, list);
showmeun();
}
}
free(temp);
return;
}
}
else { anniu(270, 410, 430, 460, "修改学生信息"); }
//-----------------------------------------------------------------------------------------
//判断“查找学生信息”按键以及功能实现函数-------------------------------------------------
if (Mxy.x >= 270 && Mxy.y <= 520 && Mxy.y >= 470 && Mxy.x <= 430)
{
clearrectangle(270, 470, 430, 520);
anniu(275, 475, 425, 515, "查找学生信息");
if (Mxy.message == WM_LBUTTONDOWN)//鼠标点击判断
{
windowtextset("查询");
if(InputBox(findFlag, 10, "请输入需要查找学生学号", NULL, NULL, 0, 0, false))
{
findtemp=findDate(list,findFlag);
if(findtemp==NULL)
{
return;
}
else
{
printnodo(findtemp);
FlushBatchDraw();//执行未完成的绘制任务。
system("PAUSE");
showmeun();
}
}
else
{
return;
}
}
}
else { anniu(270, 470, 430, 520, "查找学生信息");}
//-----------------------------------------------------------------------------------------
//判断“删除学生信息”按键以及功能实现函数-------------------------------------------------
if (Mxy.x >= 270 && Mxy.y <= 580 && Mxy.y >= 530 && Mxy.x <= 430)
{
clearrectangle(270, 530, 430, 580);
anniu(275, 535, 425, 575, "删除学生信息");
if (Mxy.message == WM_LBUTTONDOWN)//鼠标点击判断
{
windowtextset("删除");
if (InputBox(delFlag, 10, "请输入需要删除学生学号", NULL, NULL, 0, 0, false))
{
int del1 = MessageBox(0, "是否删除该学生信息!!!!", "警告!!!", MB_YESNO| MB_SYSTEMMODAL);
if (del1== IDYES)
{
delnodo(delFlag, list);
writefile(filename, list);
return;
}
else
{
return;
}
}
else
{
return;
}
}
}
else { anniu(270, 530, 430, 580, "删除学生信息"); }
//------------------------------------------------------------------------------------------
//判断“清空信息”按键以及功能实现函数------------------------------------------------------
if (Mxy.x >= 270 && Mxy.y <= 640 && Mxy.y >= 590 && Mxy.x <= 430)
{
clearrectangle(270, 590, 430, 640);
anniu(275, 595, 425, 635, "清空信息");
if (Mxy.message == WM_LBUTTONDOWN)//鼠标点击判断
{
int M1 = MessageBox(0, "是否清除数据!!!!", "警告!!!", MB_YESNO | MB_SYSTEMMODAL);
if (M1 == IDYES)
{
int M2 = MessageBox(0, "是否清除数据!!!!要谨慎!!!", "警告!!!", MB_YESNO | MB_SYSTEMMODAL);
if (M2 == IDYES)
{
int M3= MessageBox(0, "是否清除数据!!!!重要的事情说三遍!!!", "警告!!!", MB_YESNO | MB_SYSTEMMODAL);
if(M3==IDYES)
{
clearlist(list);
MessageBox(0, "已清空!", "OK", 0); return;
}
else
{
return;
}
}
else
{
return;
}
}
else
{
return;
}
}
}
else { anniu(270, 590, 430, 640, "清空信息");}
//------------------------------------------------------------------------------------------
//判断“退出系统”按键以及功能实现函数------------------------------------------------------
if (Mxy.x >= 270 && Mxy.y <= 700 && Mxy.y >= 650 && Mxy.x <= 430)
{
clearrectangle(270, 650, 430, 700);
anniu(275, 655, 425,695, "退出系统");
if (Mxy.message == WM_LBUTTONDOWN)//鼠标点击判断
{
writefile(filename, list);//写入文件
exit(0);//退出
}
}
else { anniu(270, 650, 430, 700, "退出系统");}
}
flushmessage(EM_MOUSE); EndBatchDraw();
}
void anniu(int x,int y,int xl,int yl,const char* i)//设置按钮图形函数
{
int tempx, tempy;
solidroundrect(x, y, xl, yl, 9, 9);//画无填充矩形
tempx = x + (xl - x - textwidth(i)) / 2;//求写文字起点的x,使其在矩形居中
tempy = y + (yl - y - textheight(i)) / 2;//求写文字起点的y,使其矩形居中
outtextxy(tempx, tempy, i);//输出文字
}
void showmeun()//显示菜单函数
{
initgraph(700, 720);//初始化700x700的窗口
setbkcolor(LIGHTGRAY);//设置背景浅灰
cleardevice();//清屏
setfillcolor(GREEN);//设置填充颜色。。。。。绿色
settextcolor(MAGENTA);//设置字体颜色。。。。紫色
setbkmode(TRANSPARENT);//设置字体无背景
settextstyle(50, 0, "黑体");//设置字体大小
outtextxy(100, 120, "超牛简易学生管理系统");//输出
settextstyle(0, 0, "黑体");//设置字体大小
settextcolor(RED);//设置字体颜色。。。。红
}
void jindutiao()//进度条动画函数
{
int k=0;
initgraph(600,30);
HWND jj = GetHWnd();
setfillcolor(GREEN);
SetWindowText(jj,"请稍等加载中......");
while (1)//循环画有填充的绿色矩形,使其递增长
{
solidrectangle(0,0,k,30);
k++;
Sleep(3);//暂停3ms
if (k > 600)//到规定长度跳出循环
{
break;
}
}
SetWindowText(jj, "好了宝贝");
setbkmode(TRANSPARENT);//设置字体无背景
outtextxy(150, 10, "加载完成,按回车键进入系统。。。。。。");
system("PAUSE");//暂停
}
void Dateprint()//查看信息时操作函数
{
stu* temp,*temp1;
char s[8];
int page = 1;
temp=printlist(list);
while (1)
{ExMessage Pxy;
BeginBatchDraw();
if (peekmessage(&Pxy, EM_MOUSE))
{
if (Pxy.x >= 290 && Pxy.y <= 710 && Pxy.y >= 690 && Pxy.x <= 410)//查看信息下的退出按键
{
clearrectangle(290, 690, 410, 710);
anniu(295, 695, 405, 705, "退出");
if (Pxy.message == WM_LBUTTONDOWN)
{
break;
}
}
else { anniu(290, 690, 410, 710, "退出"); }
if (Pxy.x >= 10 && Pxy.y <= 710 && Pxy.y >= 690 && Pxy.x <= 130)//查看信息下的上一页按键
{
clearrectangle(10, 690, 130, 710);
anniu(15, 695, 125, 705, "上一页");
if (Pxy.message == WM_LBUTTONDOWN)
{
temp1 = temp;
temp = lastprintlist(list, temp);
if (temp == NULL || temp1 == temp)
{
continue;
}
temp = printlist(temp);
page--;
FlushBatchDraw();
}flushmessage(EM_MOUSE);
}
else { anniu(10, 690, 130, 710, "上一页"); }
if (Pxy.x >= 570 && Pxy.y <= 710 && Pxy.y >= 690 && Pxy.x <= 690)//查看信息下的下一页按键
{
clearrectangle(570, 690, 690, 710);
anniu(575, 695, 685, 705, "下一页");
if (Pxy.message == WM_LBUTTONDOWN)
{
if (temp == NULL)
{
continue;
}
temp = printlist(temp);
page++;
FlushBatchDraw();
}flushmessage(EM_MOUSE);
}
else { anniu(570, 690, 690, 710, "下一页"); }
clearrectangle(450, 690, 550, 710);
sprintf(s, "第%d页", page);
outtextxy(480, 695, s);
EndBatchDraw();
}
}
}
int main()
{
readfile(filename, list);//读取文件数据
jindutiao();//进度条
graphdefaults();//重置视图、当前点、绘图色、背景色、线形、填充样式、字体为默认值。
showmeun();//菜单显示
while (1)
{
showanniuANDin();//按钮显示并操作
windowtextset("很厉害的管理系统!!!!!");//设置句柄
}
return 0;
}