基于MFC(C++)实现(界面)学委作业管理系统 ♻️ 资源大小633KB➡️资源下载https://download.csdn.net/download/s1t16/87430300学委作业管理系统一、概述1.1 开发环境学委作业管理系统在 Microsoft Visual Studio 2013 编译器开发的 MFC 项目计算机使用的系统是 window10。1.2 基本原理与技术要求熟悉文件读写、mfc 基本知识、c 类运用、链表使用、排序算法、Microsoft Visual Studio 2013 编译器的使用。1.3 需求说明学委作业管理系统要求实现五大功能部分分别是身份登录部分、管理员部分、学委部分、学生部分、文件储存部分。身份登陆的功能部分要求进入者进行身份认证防止个人信息泄露或他人篡改数据管理员部分的功能有对班级的增删改查、班级里的学生的增删改查功能学委、学生的身份设置学委部分的功能比较多老师布置的作业发布给学生对发布的作业有增删改查的功能、对学生提交的作业有增删改查的功能对学生作业的查询还可以按照不同的方式进行排序、学生提交情况的浏览学生部分的功能查看学委发布的作业和学生本人的提交情况文件存储的功能部分对系统正常运行提供数据支持。二、程序概要设计2.1 各功能完成情况系统已经完成了需求的所有功能。为完成功能需求学委作业管理系统设置了四个对话框窗口分别为登陆窗口、管理员窗口、学委窗口、学生窗口五个类保存数据分别是 Assignment 类、Homework 类、ClassList 类、Course 类、Person 类。窗口具体实现代码分别在 JCSDlg 类、adDlg 类、studiesDlg 类、strudentDlg 类中完成了相应的响应和具体功能实现。登陆窗口用户需要输入正确的账号和密码并选择身份才能登陆成功。当用户输入错误信息时弹出显示“输入有误”的提示框。管理员窗口实现对班级和学生的增删改查功能。管理员的账号和密码均为 000由程序员设置用户不能修改。程序从文件中读取班级信息和学生信息班级信息显示在设置的班级 listBox 中当选择某班级时在学生 listBox 中显示该班学生添加班级功能在对应的输入框中输入班级名称当该班级在数据文件中未存在时保存该班级若该班级已存在则弹出“已存在班级不可重复”的提示框查询班级当班级存在时在班级 list Box 中该班级高亮显示若不存在则弹出“未找到班级”的提示框修改班级该功能用于修改已有的班级名称当输入班级未在数据文件中找到时弹出“未找到班级”的提示框当找到时提示修改成功添加或修改学生信息功能用户填写相关信息内容当选择添加功能时遍历数据文件查看学生学号是否重复若文件中未有则添加成功否在提示失败。当选择修改功能时以学号作为基础找到该学生修改除学号以外的信息查询学生功能与查询班级功能一样删除功能用户在 list Box 中选择需要删除的信息然后按下删除键即可。学委对话窗口实现对作业和学生提交的作业增删改查功能。程序默认当用户进入学委对话框时学生或课程 listBox 显示课程名称学生可以在 ComboBox 中选择显示学生或课程当在学生或课程 List Box 选择相应的选项时该选项的内容会在详细内容 ListBox 展示查询功能在时间范围或课程名称中输入对应的时间范围或作业课程名称单击排序顺序单选按钮即可查到相关信息学生提交作业查询同理发布或更改作业填写相关信息然后点击发布或更改即可完成相应功能并把添加或更改的数据更改到数据文件中保存更改或添加同学提交的作业也同理作业统计功能显示每个学委发布的作业提交人数和班级总人数。学生对话窗口实现学生查看和提交作业的功能提交情况 listBox 显示该学生已经提交了的作业数据提交业学生在提交作业部分填写相应的内容点击提交即可保存到数据文件中作业公告显示学委发布的作业提醒学生做作业。数据保存部分Person 类保存个人信息、Assignment 类保存学委发布的作业信息、Homework 类保存学生提交信息、ClassList 类保存班级名称信息、Course 类保存课程名称信息。Person 类信息、Assignment 类信息和 homework 类信息以班级名称、学生学号作为中间媒介联系起来组成完整的信息网络完整保存每个学生的个人信息。2.2 程序流程图三、程序详细设计3.1 界面设计与数据传输通过创建 MFC 项目以对话框作为窗口的主体使用了静态文本框、编辑框、组合框、列表框、单选框、按钮等控件。从界面输入的数据有两种方法可以在后端代码中获取一种是调用 UpdateDatabool *bl方法把 bool 值设为 true 则可在编辑框绑定的变量中获取到对应输入的数据。另一种是通过 GetDlgItem(int nID)GetWindowText(CString cstring)获取到编辑框的数据并赋值给 cstring 提供给程序运行。下面介绍的各种操作需要从界面获取信息的均以这两种方法。3.2 数据保存与使用数据的保存采用文件保存方式。在 mfc 中类之间很难通过传参的方式进行数据传输所以采用了静态指针进行全局传参。把读取到的数据存放到链表中用静态指针指向链表头。这样就可以通过静态指针在其他类中调用其他类中读到或改变的数据了。文件写入以 Person 为例Person 的文件写入写在了 Person 的 writePerson 成员方法里。int Person::writePerson(Person *person) { FILE *fp; if ((fp fopen(person, wb)) NULL) return 1; CString cstr( ); while (person ! NULL) { fprintf(fp, person-num); fprintf(fp, cstr); fprintf(fp, person-name); fprintf(fp, cstr); fprintf(fp, person-className); fprintf(fp, cstr); fprintf(fp, person-pw); fprintf(fp, cstr); fprintf(fp, person-status); person person-next; if (person NULL) break; fprintf(fp, cstr); }成员方法 writePerson 接收到的链表头指针创建一个文件指针用于打开指向的文件调用 fopen 函数打开 person 文件文件的打开方式是“wb”。实例一个CString 用于存放空格该空格用于间隔类成员在文件中的位置该操作是为了方便文件读取。使用 while 循环遍历传入的链表的每一个结点调用 fprintf 函数写入节点的类的成员并在下面写入上面创建的空格。到最后一个类成员使用 if 语句判断链表是否已经到了链表末尾如果到链表末尾则不再写入空格其他的 homework、assignment、classList、course 均以这种方法进行写文件。文件获取Person *readPerson new Person(); readPerson-readPerson(readPerson); Person::person readPerson; Person *per Person::person;在 JCSDlg 类中调用 Person 类的 readPerson 方法读取 person 的信息并把头指针赋值给静态 Person 指针以便其他函数调用。其他的 homework、assignment、classList、course 等文件读取也是这样在 person 类中的 readPerson 方法具体代码如下int Person::readPerson(Person *person) { FILE *fp; CString str; char buf; int status 0; int judge 1; if ((fp fopen(person, rb)) NULL) return 1; status fread(buf, sizeof(char), 1, fp); str.Format(%c, buf); person-num str; while (status 0) { status fread(buf, sizeof(char), 1, fp); str.Format(%c, buf); if (status 0 str ) { judge; if (judge 6) { person-next new Person(); person person-next; judge 1; } } else if (status 0 judge 1) person-num str; else if (status 0 judge 2) person-name str; else if (status 0 judge 3) person-className str; else if (status 0 judge 4) person-pw str; else If (Status 0 Judge 5) Person-Status Str; } rewind(fp); fclose(fp); return 0; } readPerson成员函数从参数中接收到链表头创建文件指针fp用于指向文件、CString类型变量str用于暂存读出来的字符串、char类型变量buf用于存放从文件中读出的字符、int变量status和judge变量分别用于判断文件读出情况和读出的字符串一个要赋值给person类的哪一个变量。程序首先调用fopen函数person文件打开方式为rb。调用fread函数把读出的字符赋值给buf且把当前状态赋值给statusstr调用Format函数把读出的字符转成CString类型在把str连接到person的第一个成员变量中当status0是进入while循环每当while循环一次就调用foread函数把读出的字符赋值给buf且把当前状态赋值给statusstr调用Format函数把读出的字符转成CString类型当转换为CString时可以分六种情况的一种是判断status是否大于0且str是否等于空格如果是judge然后判断judge是否大于6如果是创建新结点把上一结点的next赋值为该节点的地址并把judge赋值为1。其他的else if用于判断str应该连接到person的哪一个成员变量中这里就不一一细说了。3.3 用户登陆从上面文件读取可以知道读取的信息链表有对应的静态指针指着链头利用链头遍历 person 数据获取每个用户的密码、账号和身份与用户输入的账号、密码和单选框的身份选择是否匹配若匹配设置 person 的静态 who 指针指向登陆用户。但如果为管理员用户则有静态 who 指针指向该结点。创建子窗口并进入用户界面。以学委登陆为例per Person::person; while (per! NULL) { if (per-num num per-pw pw per-status 学委) { Person::who per; StudiesDlg *studies new StudiesDlg(); studies-Create(IDD_DIALOG3, this); studies-ShowWindow(SW_SHOW); judge 0; break; } per per-next; }程序获取通过 Person 的静态链表把指针链表头赋值给 per用 whil 循环遍历 per每遍历一个节点就调用一次 if 语句判断输入的账号、密码是否正确身份是否是学委若不正确通过节点移动遍历下一个节点直至到节点全部遍历完。若正确把该节点赋值给 Person 的一个静态指针 who以便在学委的用户界面类中可以辨别出哪位学委登陆。创建 StudiesDlg 类指针 studies用于实例学委用户界面类studies 调用 Create 方法创建窗口调用 Showindow 参数为SW_SHOW 设置窗口打开方式judge 是用来判断是否登陆成功。3.4 删除功能当选择删除按钮是系统将执行相应的删除操作学委作业管理系统有许多的删除操作但大致都用了相同的算法。再 listBox 中获取要删除的内容把内容分隔成相应的一个类成员对应的数据以这些数据作为判断条件找去要删的数据在链表中的位置并删除该节点。代码如下ClassList *cl ClassList::classList; ClassList *copy cl; while (cl-next ! NULL) { if (cl-className className) { if (copy ! cl) { copy-next cl-next; delete cl;//释放删掉的空间 cl ClassList::classList; cl-writeClassList(cl); m_clasListBox.DeleteString(index); MessageBox(删除成功); return; } else { cl cl-next; delete copy; cl-writeClassList(cl); m_clasListBox.DeleteString(index); ClassList::classList cl; MessageBox(删除成功); return; } } copy cl; cl cl-next; }这段代码是以删除班级为例从静态指针中获取班级链表表头并使用指针 copy 保存指针副本从表头首节点开始遍历。每遍历一个节点就调用 if 判断该节点是否为要删除节点若不是 copy 指针保存该节点的副本表头 cl 指针向下移直到表头指针为 NULL。若满足 if 条件则要分两种情况第一种是副本 copy 等于头指针说明该要删除的节点为链表的首节点这时使链表的头指针 cl 下移调用 ClassList 类的 writeClassListClassList *classList方法保存数据调用delete 语句删除 copy 指针所指向的节点并提示删除成功。另一种情况使该节点不使链表的首节点copy 保存了上一节点的地址把 copy-next 赋值为 cl-next 使链表跳过要删除的 cl 节点直接与 cl 下一个节点相连然后使用 delete 语句输出 cl 指向节点的空间完成删除功能并提示删除成功。其它的学生、课程、学委发布的作业、学生提交的作业的删除的算法大致一样这里就不一一细说了。3.5 添加功能当填入相应信息并按下添加按钮时程序将执行添加功能。添加功能先以输入的内容作为判断条件遍历相应的链表查看添加的信息是否在链表中已经存在。若存在则弹出提示已经存在。若不存在则执行添加功能把添加信息添加到链表中并保存到文件和显示到 listBox 中。以添加班级为例while (head-next ! NULL) { if (head-className className) { MessageBox(已存在班级不可重复); return; } head head-next; } ClassList *cl new ClassList(); cl-className className; head ClassList::classList; head ClassList::classList; if (head NULL) { head cl; head-writeClassList(head); ClassList::classList head; m_clasListBox.AddString(className); MessageBox(添加成功); return; } cl-next head-next; head-next cl; m_clasListBox.AddString(className); head-writeClassList(head); MessageBox(添加成功);当链表为空链表时需把静态指针指向新创的对象并保存到文件中当链表不为空时把新创的类添加到链表中并重新保存链表到文件中。在对应的 ListBox 中显示添加的信息。3.6 修改功能班级名称修改是先输入原班级名称和新班级名称到链表中匹配是否存在原班级若存在修改班级名称和在修改 person 类链表中学生的班级信息也同样要改变并保存到文件中。若没有则弹出提示。其他的学生添加作业修改、学委发布作业修改、学生修改都是以特定的能唯一标识信息作为判断条件到对应链表中查找是否有该标识在链表中的某一结点除了唯一标识外其他的由新输入的数据代换并保存到文件中。特别在作为管理员修改学生信息时还要修改该学生提交的作业把作业的班级改为修改后的班级。以修改班级为例ClassList *cl ClassList::classList; while (cl! NULL) { if (cl-className beforName) { cl-className afterName; break; } cl cl-next; } cl ClassList::classList; cl-writeClassList(cl); Person *per Person::person; while (per ! NULL) { if (per-className beforName) { per-className afterName; } per per-next; } per Person::person; per-writePerson(per); MessageBox(修改成功);3.7 查找与排序班级名称和学生查找是在管理员窗口中完成的当用户输入需要查找的信息并点击查找程序以输入的信息为判断条件找出链表中是否有该查找信息。若链表中存在该消息则会显示在 listBox 中。学委发布的作业或学生提交的作业有两种查找方式一是通过课程名称二是通过时间范围。学委发布作业以时间为依据进行升降排序学生提交作业以时间或提交次数为依据进行升降排序。链表的排序程序主要使用了冒泡排序。学生提交作业排序依据是在 ComboBox 选择的升降排序是由单选框选择的。学委发布作业以时间为依据是程序写定的时间是作业发布时间。以课程名查找学生提交为例Homework *ho new Homework(); Homework *copy new Homework(); Homework *head ho; Homework *homework Homework::homework; Person *per Person::who; Homework *copy new Homework(); while (homework ! NULL) { if (homework-course course homework-className per-className) { *copy *homework; ho-next copy;//第一个为空 copy new Homework(); ho ho-next; } homework homework-next; }程序开始通过静态指针获取作业链表和登陆学委的结点指针创建 ho 和 copy 指针并实例创建 head 指针指向 ho 记录头指针位置。ho 为查找出来的作业链表的头结点copy 为作为结点的存放结点调用 while 语句循环遍历 homework每遍历一个结点就调用一次 if 语句判断作业的课程名和输入的是否一致、作业的所属班级是否与学委即是 who 的一致若不正确则遍历下一个结点直至 homework 链表结尾。若正确把该结点赋值给副本 copy 对象使 ho 指向的对象的 next 成员指针指向副本 copy 结点ho 指针往下移一个结点。冒泡排序代码如下for (p head; p ! NULL; p p-next) { for (q head; q-next ! NULL; q q-next) { if (q-time q-next-time) { *t *q; q-next; q-num h-num; q-course h-course; q-No h-No; q-time h-time; q-remark h-remark; q-name h-name; q-times h-times; h-num t-num; h-course t-course; h-No t-No; h-time t-time; h-remark t-remark; h-name t-name; h-times t-times; } } }排序调换的实质是将链表前后节点的内容调换而节点指针并没有变化。3.8 作业情况统计作业情况统计功能是统计班级人数和学委发布每一科的作业完成情况然后把统计情况以文本形式输出到对话框的文本框中提供给用户阅览。人数统计是以学委班级名称为判断依据和设置一个 int 型数据 number 纪录学生人数使用 while 循环遍历 person 链表while 循环每遍历一个结点就调用一次 if 语句判断该同学是否与学委在同一班若是设置一个 number 自增加一记录人数。统计学委发布每一科作业的完成情况具体代码如下while (course ! NULL) { while (ass ! NULL) { if (ass-course course-courseName ass-className who-className) { times 0; while (homework ! NULL homework-className who-className) { if (homework-No ass-No) { times; } homework homework-next; } CString str; str.Format(%d, times); content 课目 ass-course 作业编号 ass-No 提交数目 str 次 \r\n; } homework Homework::homework; ass ass-next; } ass Assignmen::assignmen; course course-next; } GetDlgItem(IDC_EDIT18)-SetWindowTextA(content);完成学委发布的每一科作业的学生作业情况提交统计功能程序运用了三层 while 循环。最外面的是 course 链表遍历中间层的是 assignment 链表遍历最底层的是 homework 链表遍历。该程序的大致意思是遍历每一科目根据科目名称作为中间层 while 循环内 if 语句的判断依据中间层 while 的 if 除了科目名称外还有班级名作为判断依据通过筛选获得对应的作业编号。在最内层遍历 homework 链表每遍历一个结点调用一次 if 语句以中间层得到的作业编号和学委的班级名称作为判断依据如果符合条件times 记录次数当最内层遍历接收把 times 转成 CString 并添加到 content 的 CString 中作为内容输出。最外层用多一个 course 链表做循环遍历是因为当删除科目是 course 链表删除该科目但 homework 链表和 assignment 链表并没有删除该科目的相应信息作业情况统计要做的是统计现有的科目作业完成情况使用 course 链表作业筛选去掉不必要的信息。四、使用情况4.1 登陆界面使用情况登陆使用情况如右图所示。账号为可显示的输入框密码为隐秘数字后的输入框。管理员、学委、学生为单选框点击登陆账号、密码和身份正确后即可顺利进入相应的应用界面4.2 管理员界面使用情况管理员界面使用情况如上图所示。各项功能使用正常。当点击班级 listBox 时修改班级的初始会出现选择的班级名称学生 listBox 出现该班级学生名单。当点击学生 listBox 时下面修改或添加项目的编辑框会出现该学生的相应信息。4.3 学委界面使用情况学委界面使用情况该界面可分为浏览区、查找区、发布或更改作业区、更改或添加同学提交的作业区、作业提交情况统计区。在浏览区用户可以查看同学提交的作业和每个课程发布的作业当点击详细内容 listBox 时里面的内容会出现在相应的编辑框中查找区可以分为学委发布的作业查找和学生提交的作业查找。4.4 学生界面使用情况学生界面使用情况可分提交情况区、提交作业区、作业公告区。提交作业情况区展示提交该同学作业的提交情况。提交作业区用于学生提交作业。作业公告用于展示学委发布的作业。五、总结虽然题目需求都满足了但还是存在着不少的问题需要在以后的学习中改进自己做出更好的程序。此次的不足主要在于代码的重复率比较高、容错性比较差、页面布局也欠妥、在开发前没用充分做好需求分析和总体的代码实现规划、在学委窗口界面本来是加滚条把右半部分的内容放在下面但因知识欠缺失败了所以把内容强加到了右边。优点在于功能完成度高题目的所以要求已经基本完成附加题也都做了系统使用的时 mfc 项目图形界面方便了使用者操作。在系统开发过程中遇到的困难还是蛮多的如 c 的类知识、mfc 的控件使用和方法调用、CString 怎么存进文件这些都是之前我的知识储备里没有的东西。所以我要花大量的时间和精力去看书和上网查找质料学习。不过结果还是好的学到了很多知识和程序能正常运行。在这次数据结构大作业中最大的收获是学会了怎么快速的找 bug 和在尝试新的方法时可以先写一个小规模程序模型测试是否行得通。遇到 bug 是最好是写多一点输出这样能快速查出错误地方在错误附加断点测试这样能快速了解到出错原因。不要觉得小程序模型测试没什么必要和麻烦这是快速验证你的方法是否行的通的最有效方法。当你写了一大片的代码最后运行才发现方法行不通那就损失大了。所以必要的测试还是要的。总之写代码就是要有耐心和够细致才能减少出错。六、参考文献【1】 梁勇.C 程序设计原书第 3 版.出版社机械工业出版社【2】 刘锐宁 宋坤.Visual C 程序设计标准教程.出版社人民邮电出版社【3】 胡圣荣 周霭如 罗穗萍.数据结构教程与题解.清华大学出版社