Python程序设计项目 成绩信息管理系统 大学编程作业(TUST天津科技大学2021年)

Python 程序设计项目 成绩信息管理系统 大学编程作业(TUST 天津科技大学 2021 年)

一、项目简介

本成绩信息管理系统 ,我使用了 Python 丰富的第三方开源模块,如 csv、wxPython、pandas、numpy、scipy、math、matplotlib、PyInstaller 等来制作,实现了简单的增删查改逻辑,实现了成绩信息数据的简单统计分析和 csv 文件自动的存储,并且 UI 界面较为美观易用。通过这次 Python 程序设计项目的实践,我巩固了 Python 的语法知识,熟练应用了各个第三方开源模块,为之后的数学建模学习打下基础。

这个项目是我大二写的,现在回顾已经非常粗糙,分享出来一方面希望可以帮助初学者,另一方面希望能让同学们可以从目前大学中普遍毫无价值的形式主义作业中解脱出来,更加高效地学习优质计算机知识和主流编程技术,一起发扬开源精神,感受互联网技术的美好愿景。

二、项目要求

  1. 注册账号功能
    注册账号,并保存为用户名和密码.csv 文件。

  2. 登录账号功能
    登录账号,打开主界面。

  3. 取消登录功能
    取消登录,关闭登录界面。

  4. 录入成绩功能
    录入成绩,手动计算或自动计算总分和平均分,并保存为学生成绩数据.csv 文件。

  5. 查询成绩功能
    查询成绩,打开消息对话框显示结果。

  6. 修改成绩功能

  7. 删除成绩功能

  8. 统计成绩数据功能
    分析学习成绩数据,打开消息对话框显示结果,并保存为班级各科成绩数据汇总统计.csv 文件和班级学生成绩排名.csv 文件。

  9. 绘制成绩统计图功能
    绘制班级综合成绩正态分布曲线,打开消息对话框显示结果,并保存为班级综合成绩正态分布曲线.png 文件。

  10. 异常处理功能
    录入成绩时,输入非数字字符弹出对话框提示“请在成绩栏中输入数字!”,输入 0 到 100 以外的数字弹出对话框提示“请在成绩栏中输入 0~100 以内的数字!”。

  11. 数据存储位置说明
    程序运行时的数据将保存在程序运行时所在路径。

三、项目源码

程序设计思路:

  1. 用户数据和学生成绩数据的类
  2. 图形用户界面:wxPython 模块
  3. 功能实现函数:调用用户数据和学生成绩数据的类中的方法
  4. 统计数据,绘制统计图的函数:pandas 模块,matplotlib 模块
  5. 提高程序健壮性:自定义异常类和异常处理

源代码:

  1. Python 综合实验成绩信息管理系统主代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理
"""
import 图形用户界面_代码文件 as MyModule2


if __name__ == "__main__":
    score_management_app = MyModule2.wx.App()  # 初始化App
    login_interface_frame = MyModule2.LoginInterfaceFrame(parent=None, id=MyModule2.wx.ID_ANY)  # 实例LoginInterfaceFrame类,并传递参数
    login_interface_frame.Show(True)  # 显示登录窗口
    score_management_app.MainLoop()  # 调用主循环方法
  1. 用户数据和学生成绩数据的类_代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理

"""
import os
import csv


# 1.用户数据和学生成绩数据的类
class UserDate:
    """定义用户数据类"""

    def __init__(self, username="", password=""):
        """初始化属性"""
        self.username = username
        self.password = password

    def RegisterFunction(self):
        """定义注册函数"""

        result = ""

        # 判断用户名和密码.csv文件是否存在,并且在用户数据表格csv文件中初始化表头为用户名和密码
        if os.path.exists("用户名和密码.csv") is False:
            with open("用户名和密码.csv", mode="a", newline="") as user_date_csv:
                w = csv.writer(user_date_csv)
                w.writerow(["用户名", "密码"])

        # 判断用户名和密码是否输入
        if self.username == "" or self.password == "":
            result = "用户名和密码不能为空!"
        else:
            # 判断用户名是否已注册
            user_is_registered = False

            with open("用户名和密码.csv", mode="r") as user_date_csv:
                r = csv.reader(user_date_csv)
                for line_list in r:
                    if line_list != ["用户名", "密码"]:  # 用来避免第一行表头的对判断的影响
                        if self.username == line_list[0]:  # 用列表line_list的下标来获取一行中的用户名
                            user_is_registered = True
                            result = "此用户名已被注册,请重新输入用户名!"

            # 在用户数据表格csv文件中写入用户名和密码
            if user_is_registered is False:
                with open("用户名和密码.csv", mode="a", newline="") as user_date_csv:
                    w = csv.writer(user_date_csv)
                    w.writerow([self.username, self.password])
                    result = f"用户“{self.username}”注册成功!"

        return result

    def LoginFunction(self):
        """定义登录函数"""

        result = ""

        # 判断用户名和密码是否输入
        if self.username == "" or self.password == "":
            result = "用户名和密码不能为空!"
        else:
            # 判断用户名和密码.csv文件是否存在,提示用户先注册
            if os.path.exists("用户名和密码.csv") is False:
                result = "请先注册账户!"
            else:
                result = "用户名或密码错误!"
                # 在用户数据表格csv文件中查询比较用户名和密码是否一致
                with open("用户名和密码.csv", mode="r") as user_date_csv:
                    r = csv.reader(user_date_csv)
                    for line_list in r:
                        if line_list != ["用户名", "密码"]:  # 用来避免第一行表头的对判断的影响
                            if self.username == line_list[0]:  # 用列表line_list的下标来获取一行中的用户名和密码
                                if self.password == line_list[1]:
                                    result = "登录成功!"

        return result


class StudentDate:
    """定义学生数据类"""

    def __init__(self, name="", id="", score_math=0.0, score_english=0.0, score_python=0.0, score_java=0.0, score_cpp=0.0, total_score=0.0, average_score=0.0):
        """初始化属性"""
        self.name = name
        self.id = id
        self.score_math = score_math
        self.score_english = score_english
        self.score_python = score_python
        self.score_java = score_java
        self.score_cpp = score_cpp
        self.total_score = total_score
        self.average_score = average_score

    def SaveScoreFunction(self):
        """定义保存成绩函数"""

        result = ""

        # 判断学生成绩数据.csv文件是否存在,并且在用户数据表格csv文件中初始化表头为姓名,学号,高等数学,英语,Python,Java,C++,总分,平均分。
        if os.path.exists("学生成绩数据.csv") is False:
            with open("学生成绩数据.csv", mode="a", newline="") as student_score_date_csv:
                w = csv.writer(student_score_date_csv)
                w.writerow(["姓名", "学号", "高等数学", "英语", "Python", "Java", "C++", "总分", "平均分"])

        # 判断学生姓名,学号是否输入
        if self.name == "" or self.id == "":
            result = "请输入姓名和学号!"
        else:
            # 判断学号是否重复
            student_score_is_repeated = False

            with open("学生成绩数据.csv", mode="r") as student_score_date_csv:
                r = csv.reader(student_score_date_csv)
                for line_list in r:
                    if line_list != ["姓名", "学号", "高等数学", "英语", "Python", "Java", "C++", "总分", "平均分"]:  # 用来避免第一行表头的对判断的影响
                        if self.id == line_list[1]:  # 用列表line_list的下标来获取一行中的学号
                            student_score_is_repeated = True
                            result = f"学号{self.id}已重复,无法保存学生成绩,请检查学号是否正确!"

            # 在学生成绩数据表格csv文件中写入学生成绩
            if student_score_is_repeated is False:
                with open("学生成绩数据.csv", mode="a", newline="") as student_score_date_csv:
                    w = csv.writer(student_score_date_csv)
                    w.writerow([self.name, self.id, self.score_math, self.score_english, self.score_python, self.score_java, self.score_cpp, self.total_score, self.average_score])
                    result = f"学号为{self.id}的学生成绩已保存!\n\n学生成绩数据已保存至程序所在路径。\n文件名:学生成绩数据.csv"

        return result

    def FindScoreFunction(self):
        """定义查找成绩函数"""

        result = ""

        # 判断学号是否输入
        if self.id == "":
            result = "请输入要查询的学号!"
        else:
            # 判断学生成绩数据.csv文件是否存在,提示用户先录入成绩
            if os.path.exists("学生成绩数据.csv") is False:
                result = "请先录入成绩!"
            else:
                result = "未找到此学生的成绩信息!"
                # 在学生成绩数据表格csv文件中查询比较学号是否相一致
                with open("学生成绩数据.csv", mode="r") as student_score_date_csv:
                    r = csv.reader(student_score_date_csv)
                    for line_list in r:
                        if line_list != ["姓名", "学号", "高等数学", "英语", "Python", "Java", "C++", "总分", "平均分"]:  # 用来避免第一行表头的对判断的影响
                            if self.id == line_list[1]:  # 用列表line_list的下标来获取一行中的学号
                                # 找到此学生的成绩信息后,用列表line_list的下标来获取相对应的学生成绩数据
                                self.name = line_list[0]
                                self.id = line_list[1]
                                self.score_math = line_list[2]
                                self.score_english = line_list[3]
                                self.score_python = line_list[4]
                                self.score_java = line_list[5]
                                self.score_cpp = line_list[6]
                                self.total_score = line_list[7]
                                self.average_score = line_list[8]
                                result = f"已找到此学生的成绩信息!\n\n姓名:{self.name}\n学号:{self.id}\n高等数学:{self.score_math}\n英语:{self.score_english}\nPython:{self.score_python}\nJava:{self.score_java}\nC++:{self.score_cpp}\n总分:{self.total_score}\n平均分:{self.average_score}"

        return result

    def ReviseScoreFunction(self):
        """定义修改成绩函数"""
        return True

    def DeleteScoreFunction(self):
        """定义删除成绩函数"""
        return True
  1. 图形用户界面_代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理

"""
import wx
import 功能实现函数_代码文件 as MyModule3
import 统计数据_绘制统计图的函数_代码文件 as MyModule4


# 2.图形用户界面:wxPython模块
class LoginInterfaceFrame(wx.Frame):
    """定义登录界面的Frame框架类"""

    def __init__(self, parent, id):
        # 初始化Frame框架
        wx.Frame.__init__(self, parent, id, title="用户登录界面 - 成绩信息管理系统", size=(720, 480))

        # 定义登录界面的Panel面板
        login_interface_panel = wx.Panel(self)

        # 创建登录界面的文本
        self.login_title_1 = wx.StaticText(login_interface_panel, label="请输入用户名和密码")
        self.login_title_2 = wx.StaticText(login_interface_panel, label="欢迎使用成绩信息管理系统\n作者:MYXHcode")
        self.label_user = wx.StaticText(login_interface_panel, label="用户名:")
        self.text_user = wx.TextCtrl(login_interface_panel, style=wx.TE_LEFT)
        self.label_pwd = wx.StaticText(login_interface_panel, label="密    码:")
        self.text_pwd = wx.TextCtrl(login_interface_panel, style=wx.TE_PASSWORD)

        # 创建按钮,并绑定事件
        self.button_register = wx.Button(login_interface_panel, label="注册")
        self.button_register.Bind(wx.EVT_BUTTON, self.OncLickRegister)
        self.button_login = wx.Button(login_interface_panel, label="登录")
        self.button_login.Bind(wx.EVT_BUTTON, self.OncLickLogin)
        self.button_cancel = wx.Button(login_interface_panel, label="取消")
        self.button_cancel.Bind(wx.EVT_BUTTON, self.OncLickCancel)

        # 添加容器,容器中控件按纵向并排排列
        vsizer_user = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_user.Add(self.label_user, proportion=0, flag=wx.ALL, border=5)
        vsizer_user.Add(self.text_user, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        vsizer_pwd = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_pwd.Add(self.label_pwd, proportion=0, flag=wx.ALL, border=5)
        vsizer_pwd.Add(self.text_pwd, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        # 添加容器,容器中控件按横向并排排列
        hsizer_button = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_button.Add(self.button_register, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        hsizer_button.Add(self.button_login, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        hsizer_button.Add(self.button_cancel, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all.Add(self.login_title_1, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=15)
        vsizer_all.Add(vsizer_user, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=65)
        vsizer_all.Add(vsizer_pwd, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=65)
        vsizer_all.Add(hsizer_button, proportion=0, flag=wx.ALIGN_CENTER | wx.TOP, border=25)
        vsizer_all.Add(self.login_title_2, proportion=20, flag=wx.BOTTOM | wx.TOP | wx.LEFT, border=15)
        login_interface_panel.SetSizer(vsizer_all)

    # 定义按钮函数
    def OncLickRegister(self, event):
        """点击按钮,执行方法"""
        MyModule3.RegisterFunctionForwx(self, event)

    def OncLickLogin(self, event):
        """点击按钮,执行方法"""
        MyModule3.LoginFunctionForwx(self, event)

    def OncLickCancel(self, event):
        """点击按钮,执行方法"""
        MyModule3.CancelLoginFunctionForwx(self, event)


class MainFrame(wx.Frame):
    """定义主界面的Frame框架类"""

    def __init__(self, parent, id):
        # 初始化Frame框架
        wx.Frame.__init__(self, parent, id, "主界面 - 成绩信息管理系统", size=(720, 480))

        # 定义主界面的Panel面板
        main_panel = wx.Panel(self)

        # 创建主界面的文本
        self.main_title_1 = wx.StaticText(main_panel, label="欢迎使用成绩信息管理系统")
        self.main_title_2 = wx.StaticText(main_panel, label="请选择下列功能:")
        self.main_title_3 = wx.StaticText(main_panel, label="\t成绩记录:")
        self.main_title_4 = wx.StaticText(main_panel, label="\t成绩统计:")
        self.main_title_5 = wx.StaticText(main_panel, label="作者:MYXHcode")

        # 创建按钮,并绑定事件
        self.button_score_entry = wx.Button(main_panel, label="成绩录入")
        self.button_score_entry.Bind(wx.EVT_BUTTON, self.OncLickScoreEntry)
        self.button_score_find = wx.Button(main_panel, label="成绩查询")
        self.button_score_find.Bind(wx.EVT_BUTTON, self.OncLickScoreFind)
        self.button_score_revise = wx.Button(main_panel, label="成绩修改")
        self.button_score_revise.Bind(wx.EVT_BUTTON, self.OncLickScoreRevise)
        self.button_score_delete = wx.Button(main_panel, label="成绩删除")
        self.button_score_delete.Bind(wx.EVT_BUTTON, self.OncLickScoreDelete)
        self.button_score_statistics = wx.Button(main_panel, label="统计成绩数据")
        self.button_score_statistics.Bind(wx.EVT_BUTTON, self.OncLickStatistics)
        self.button_score_summary_graph = wx.Button(main_panel, label="绘制成绩统计图")
        self.button_score_summary_graph.Bind(wx.EVT_BUTTON, self.OncLickScoreSummaryGraph)

        # 添加容器,容器中控件按纵向并排排列
        vsizer_button_score = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_button_score.Add(self.button_score_entry, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        vsizer_button_score.Add(self.button_score_find, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        vsizer_button_score.Add(self.button_score_revise, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        vsizer_button_score.Add(self.button_score_delete, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        # 添加容器,容器中控件按横向并排排列
        hsizer_button_statistics = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_button_statistics.Add(self.button_score_statistics, proportion=0, flag=wx.ALIGN_CENTER, border=5)
        hsizer_button_statistics.Add(self.button_score_summary_graph, proportion=0, flag=wx.ALIGN_CENTER, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all.Add(self.main_title_1, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=15)
        vsizer_all.Add(self.main_title_2, proportion=0, flag=wx.BOTTOM | wx.LEFT | wx.RIGHT, border=15)
        vsizer_all.Add(self.main_title_3, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=65)
        vsizer_all.Add(vsizer_button_score, proportion=0, flag=wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all.Add(self.main_title_4, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=65)
        vsizer_all.Add(hsizer_button_statistics, proportion=0, flag=wx.ALIGN_CENTER | wx.BOTTOM, border=45)
        vsizer_all.Add(self.main_title_5, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.LEFT, border=15)
        main_panel.SetSizer(vsizer_all)

    # 定义按钮函数
    def OncLickScoreEntry(self, event):
        """点击按钮,执行方法"""
        score_entry_frame = ScoreEntryFrame(parent=None, id=wx.ID_ANY)  # 实例ScoreEntryFrame类,并传递参数
        score_entry_frame.Show(True)  # 显示窗口

    def OncLickScoreFind(self, event):
        """点击按钮,执行方法"""
        score_find_frame = ScoreFindFrame(parent=None, id=wx.ID_ANY)  # 实例ScoreFindFrame类,并传递参数
        score_find_frame.Show(True)  # 显示窗口

    def OncLickScoreRevise(self, event):
        """点击按钮,执行方法"""
        return True

    def OncLickScoreDelete(self, event):
        """点击按钮,执行方法"""
        return True

    def OncLickStatistics(self, event):
        """点击按钮,执行方法"""
        MyModule4.StatisticalPerformanceDataFunctionForwx(self, event)

    def OncLickScoreSummaryGraph(self, event):
        """点击按钮,执行方法"""
        MyModule4.DrawingStatisticalGraphsFunctionForwx(self, event)


class ScoreEntryFrame(wx.Frame):
    """定义成绩录入界面的Frame框架类"""

    def __init__(self, parent, id):
        # 初始化Frame框架
        wx.Frame.__init__(self, parent, id, "成绩录入界面 - 成绩信息管理系统", size=(900, 600))

        # 定义成绩录入界面的Panel面板
        score_entry_panel = wx.Panel(self)

        # 定义成绩录入界面的文本
        self.score_entry_title_1 = wx.StaticText(score_entry_panel, label="成绩录入功能")
        self.score_entry_title_2 = wx.StaticText(score_entry_panel, label="请输入你的姓名:")
        self.score_entry_title_3 = wx.StaticText(score_entry_panel, label="请输入你的学号:")
        self.score_entry_title_4 = wx.StaticText(score_entry_panel, label="请输入你的各科成绩:")
        self.score_entry_title_5 = wx.StaticText(score_entry_panel, label="作者:MYXHcode")
        self.label_name = wx.StaticText(score_entry_panel, label="姓名:")
        self.text_name = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_id = wx.StaticText(score_entry_panel, label="学号:")
        self.text_id = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_score_math = wx.StaticText(score_entry_panel, label="高等数学:")
        self.text_score_math = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_score_english = wx.StaticText(score_entry_panel, label="英   语:")
        self.text_score_english = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_score_python = wx.StaticText(score_entry_panel, label="Python:")
        self.text_score_python = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_score_java = wx.StaticText(score_entry_panel, label="J a v a:")
        self.text_score_java = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_score_cpp = wx.StaticText(score_entry_panel, label="C + +:")
        self.text_score_cpp = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_total_score = wx.StaticText(score_entry_panel, label="总   分:")
        self.text_total_score = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_average_score = wx.StaticText(score_entry_panel, label="平均分:")
        self.text_average_score = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)

        # 创建按钮,并绑定事件
        self.button_total_score = wx.Button(score_entry_panel, label="计算总分")
        self.button_total_score.Bind(wx.EVT_BUTTON, self.OncLickTotalScore)
        self.button_average_score = wx.Button(score_entry_panel, label="计算平均分")
        self.button_average_score.Bind(wx.EVT_BUTTON, self.OncLickAverageScore)
        self.button_save = wx.Button(score_entry_panel, label="保存成绩")
        self.button_save.Bind(wx.EVT_BUTTON, self.OncLickSaveScore)

        # 添加容器,容器中控件按横向并排排列
        hsizer_name = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_name.Add(self.label_name, proportion=0, flag=wx.ALL, border=5)
        hsizer_name.Add(self.text_name, proportion=1, flag=wx.ALL, border=5)
        hsizer_id = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_id.Add(self.label_id, proportion=0, flag=wx.ALL, border=5)
        hsizer_id.Add(self.text_id, proportion=1, flag=wx.ALL, border=5)
        hsizer_score_math = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_score_math.Add(self.label_score_math, proportion=0, flag=wx.ALL, border=5)
        hsizer_score_math.Add(self.text_score_math, proportion=1, flag=wx.ALL, border=5)
        hsizer_score_english = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_score_english.Add(self.label_score_english, proportion=0, flag=wx.ALL, border=5)
        hsizer_score_english.Add(self.text_score_english, proportion=1, flag=wx.ALL, border=5)
        hsizer_score_python = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_score_python.Add(self.label_score_python, proportion=0, flag=wx.ALL, border=5)
        hsizer_score_python.Add(self.text_score_python, proportion=1, flag=wx.ALL, border=5)
        hsizer_score_java = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_score_java.Add(self.label_score_java, proportion=0, flag=wx.ALL, border=5)
        hsizer_score_java.Add(self.text_score_java, proportion=1, flag=wx.ALL, border=5)
        hsizer_score_cpp = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_score_cpp.Add(self.label_score_cpp, proportion=0, flag=wx.ALL, border=5)
        hsizer_score_cpp.Add(self.text_score_cpp, proportion=1, flag=wx.ALL, border=5)
        hsizer_total_score = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_total_score.Add(self.label_total_score, proportion=0, flag=wx.ALL, border=5)
        hsizer_total_score.Add(self.text_total_score, proportion=1, flag=wx.ALL, border=5)
        hsizer_average_score = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_average_score.Add(self.label_average_score, proportion=0, flag=wx.ALL, border=5)
        hsizer_average_score.Add(self.text_average_score, proportion=1, flag=wx.ALL, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_button = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_button.Add(self.button_total_score, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5)
        vsizer_button.Add(self.button_average_score, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5)
        vsizer_button.Add(self.button_save, proportion=0, flag=wx.LEFT, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all_left = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all_left.Add(self.score_entry_title_2, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15)
        vsizer_all_left.Add(hsizer_name, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(self.score_entry_title_3, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15)
        vsizer_all_left.Add(hsizer_id, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(self.score_entry_title_4, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15)
        vsizer_all_left.Add(hsizer_score_math, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_score_english, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_score_python, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_score_java, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_score_cpp, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_total_score, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_average_score, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all_right = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all_right.Add(vsizer_button, proportion=0, flag=wx.ALIGN_CENTER | wx.TOP, border=15)
        # 添加容器,容器中控件按横向并排排列
        hsizer_all_middle = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_all_middle.Add(vsizer_all_left, proportion=0, flag=wx.ALIGN_CENTER, border=20)
        hsizer_all_middle.Add(vsizer_all_right, proportion=0, flag=wx.ALIGN_CENTER, border=20)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all.Add(self.score_entry_title_1, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=20)
        vsizer_all.Add(hsizer_all_middle, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=20)
        vsizer_all.Add(self.score_entry_title_5, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.LEFT, border=15)
        score_entry_panel.SetSizer(vsizer_all)

    # 定义按钮函数
    def OncLickTotalScore(self, event):
        """点击按钮,执行方法"""
        MyModule3.TotalScoreForwx(self, event)

    def OncLickAverageScore(self, event):
        """点击按钮,执行方法"""
        MyModule3.AverageScoreForwx(self, event)

    def OncLickSaveScore(self, event):
        """点击按钮,执行方法"""
        MyModule3.SaveScoreFunctionForwx(self, event)


class ScoreFindFrame(wx.Frame):
    """定义成绩查询界面的Frame框架类"""

    def __init__(self, parent, id):
        # 初始化Frame框架
        wx.Frame.__init__(self, parent, id, "成绩查询界面 - 成绩信息管理系统", size=(720, 480))

        # 定义成绩查询界面的Panel面板
        score_find_panel = wx.Panel(self)

        # 定义成绩查询界面的文本
        self.score_find_title_1 = wx.StaticText(score_find_panel, label="成绩查询功能")
        self.score_find_title_2 = wx.StaticText(score_find_panel, label="请输入要查询的学号:")
        self.score_find_title_3 = wx.StaticText(score_find_panel, label="作者:MYXHcode")
        self.label_id = wx.StaticText(score_find_panel, label="学号:")
        self.text_id = wx.TextCtrl(score_find_panel, style=wx.TE_LEFT)

        # 创建按钮,并绑定事件
        self.button_find = wx.Button(score_find_panel, label="查询成绩")
        self.button_find.Bind(wx.EVT_BUTTON, self.OncLickFindScore)

        # 添加容器,容器中控件按横向并排排列
        hsizer_id = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_id.Add(self.label_id, proportion=0, flag=wx.ALL, border=5)
        hsizer_id.Add(self.text_id, proportion=1, flag=wx.ALL, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_button = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_button.Add(self.button_find, proportion=0, flag=wx.LEFT, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all_left = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all_left.Add(self.score_find_title_2, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15)
        vsizer_all_left.Add(hsizer_id, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all_right = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all_right.Add(vsizer_button, proportion=0, flag=wx.ALIGN_CENTER | wx.TOP, border=15)
        # 添加容器,容器中控件按横向并排排列
        hsizer_all_middle = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_all_middle.Add(vsizer_all_left, proportion=0, flag=wx.ALIGN_CENTER, border=20)
        hsizer_all_middle.Add(vsizer_all_right, proportion=0, flag=wx.ALIGN_CENTER, border=20)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all.Add(self.score_find_title_1, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=20)
        vsizer_all.Add(hsizer_all_middle, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=20)
        vsizer_all.Add(self.score_find_title_3, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.LEFT, border=15)
        score_find_panel.SetSizer(vsizer_all)

    # 定义按钮函数
    def OncLickFindScore(self, event):
        """点击按钮,执行方法"""
        MyModule3.FindScoreFunctionForwx(self, event)
  1. 功能实现函数_代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理

"""
import wx
import 用户数据和学生成绩数据的类_代码文件 as MyModule1
import 图形用户界面_代码文件 as MyModule2
import 提高程序健壮性_代码文件 as MyModule5


# 3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
def RegisterFunctionForwx(self, event):
    """定义注册函数给wx"""

    username = self.text_user.GetValue()  # 获取输入的用户名
    password = self.text_pwd.GetValue()  # 获取输入的密码

    user_date = MyModule1.UserDate(username, password)  # 实例化UserDate类
    message = user_date.RegisterFunction()  # 调用注册函数

    wx.MessageBox(message, caption="注册提示")  # 弹出提示框


def LoginFunctionForwx(self, event):
    """定义登录函数给wx"""

    username = self.text_user.GetValue()  # 获取输入的用户名
    password = self.text_pwd.GetValue()  # 获取输入的密码

    user_date = MyModule1.UserDate(username, password)  # 实例化UserDate类
    message = user_date.LoginFunction()  # 调用登录函数

    if message == "登录成功!":
        wx.MessageBox(message, caption="登录提示")  # 弹出提示框
        MyModule2.LoginInterfaceFrame.Close(self)  # 关闭登录窗口
        main_frame = MyModule2.MainFrame(parent=None, id=wx.ID_ANY)  # 实例MainFrame类,并传递参数
        main_frame.Show(True)  # 显示主窗口
    else:
        wx.MessageBox(message, caption="登录提示")  # 弹出提示框


def CancelLoginFunctionForwx(self, event):
    """定义取消登录函数给wx"""
    self.text_user.SetValue("")  # 清空输入的用户名
    self.text_pwd.SetValue("")  # 清空输入的密码
    MyModule2.LoginInterfaceFrame.Close(self)  # 关闭登录窗口


def TotalScoreForwx(self, event):
    """定义计算总分函数给wx"""

    try:
        # 当输入非数字时引发异常
        score_math = float(self.text_score_math.GetValue())  # 获取输入的高等数学成绩
        score_english = float(self.text_score_english.GetValue())  # 获取输入的英语成绩
        score_python = float(self.text_score_python.GetValue())  # 获取输入的Python成绩
        score_java = float(self.text_score_java.GetValue())  # 获取输入的Java成绩
        score_cpp = float(self.text_score_cpp.GetValue())  # 获取输入的C++成绩

        # 当输入0~100以外的数字时引发异常
        if score_math < 0 or score_math > 100:
            raise MyModule5.NumericalRangeError
        elif score_english < 0 or score_english > 100:
            raise MyModule5.NumericalRangeError
        elif score_python < 0 or score_python > 100:
            raise MyModule5.NumericalRangeError
        elif score_java < 0 or score_java > 100:
            raise MyModule5.NumericalRangeError
        elif score_cpp < 0 or score_cpp > 100:
            raise MyModule5.NumericalRangeError

        # 计算总分,并输入到总分栏
        total_score = (score_math + score_english + score_python + score_java + score_cpp)
        self.text_total_score.SetValue(f"{total_score}")
    except ValueError:  # 捕获异常
        message = "请在成绩栏中输入数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框
    except MyModule5.NumericalRangeError:  # 捕获异常
        message = "请在成绩栏中输入0~100以内的数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框


def AverageScoreForwx(self, event):
    """定义计算平均分函数给wx"""

    try:
        # 当输入非数字时引发异常
        score_math = float(self.text_score_math.GetValue())  # 获取输入的高等数学成绩
        score_english = float(self.text_score_english.GetValue())  # 获取输入的英语成绩
        score_python = float(self.text_score_python.GetValue())  # 获取输入的Python成绩
        score_java = float(self.text_score_java.GetValue())  # 获取输入的Java成绩
        score_cpp = float(self.text_score_cpp.GetValue())  # 获取输入的C++成绩

        # 当输入0~100以外的数字时引发异常
        if score_math < 0 or score_math > 100:
            raise MyModule5.NumericalRangeError
        elif score_english < 0 or score_english > 100:
            raise MyModule5.NumericalRangeError
        elif score_python < 0 or score_python > 100:
            raise MyModule5.NumericalRangeError
        elif score_java < 0 or score_java > 100:
            raise MyModule5.NumericalRangeError
        elif score_cpp < 0 or score_cpp > 100:
            raise MyModule5.NumericalRangeError

        # 计算平均分,并输入到平均分栏
        total_score = (score_math + score_english + score_python + score_java + score_cpp)
        average_score = (total_score / 5)
        self.text_average_score.SetValue(f"{average_score}")
    except ValueError:  # 捕获异常
        message = "请在成绩栏中输入数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框
    except MyModule5.NumericalRangeError:  # 捕获异常
        message = "请在成绩栏中输入0~100以内的数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框


def SaveScoreFunctionForwx(self, event):
    """定义保存成绩函数给wx"""

    name = self.text_name.GetValue()  # 获取输入的姓名
    id = self.text_id.GetValue()  # 获取输入的学号

    try:
        # 当输入非数字时引发异常
        score_math = float(self.text_score_math.GetValue())  # 获取输入的高等数学成绩
        score_english = float(self.text_score_english.GetValue())  # 获取输入的英语成绩
        score_python = float(self.text_score_python.GetValue())  # 获取输入的Python成绩
        score_java = float(self.text_score_java.GetValue())  # 获取输入的Java成绩
        score_cpp = float(self.text_score_cpp.GetValue())  # 获取输入的C++成绩
        total_score = self.text_total_score.GetValue()  # 获取输入的总分
        average_score = self.text_average_score.GetValue()  # 获取输入的平均分

        # 当输入0~100以外的数字时引发异常
        if score_math < 0 or score_math > 100:
            raise MyModule5.NumericalRangeError
        elif score_english < 0 or score_english > 100:
            raise MyModule5.NumericalRangeError
        elif score_python < 0 or score_python > 100:
            raise MyModule5.NumericalRangeError
        elif score_java < 0 or score_java > 100:
            raise MyModule5.NumericalRangeError
        elif score_cpp < 0 or score_cpp > 100:
            raise MyModule5.NumericalRangeError

        # 自动计算总分和平均分
        total_score_auto = (score_math + score_english + score_python + score_java + score_cpp)
        average_score_auto = (total_score_auto / 5)

        # 改正用户输入错误的总分和平均分
        if total_score != total_score_auto or average_score != average_score_auto:
            total_score = total_score_auto
            average_score = average_score_auto
            self.text_total_score.SetValue(f"{total_score}")
            self.text_average_score.SetValue(f"{average_score}")

        student_date = MyModule1.StudentDate(name, id, score_math, score_english, score_python, score_java, score_cpp, total_score, average_score)  # 实例化StudentDate类
        message = student_date.SaveScoreFunction()  # 调用保存成绩函数
        wx.MessageBox(message, caption="成绩录入结果")  # 弹出提示框
    except ValueError:  # 捕获异常
        message = "请在成绩栏中输入数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框
    except MyModule5.NumericalRangeError:  # 捕获异常
        message = "请在成绩栏中输入0~100以内的数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框


def FindScoreFunctionForwx(self, event):
    """定义查询成绩函数给wx"""

    id = self.text_id.GetValue()  # 获取输入的学号

    student_date = MyModule1.StudentDate(id=id)  # 实例化StudentDate类
    message = student_date.FindScoreFunction()  # 调用查询成绩函数

    if message == "请输入要查询的学号!":
        wx.MessageBox(message, caption="提示")  # 弹出提示框
    else:
        wx.MessageBox(message, caption="成绩查询结果")  # 弹出提示框
  1. 统计数据绘制统计图的函数代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理

"""
import os
import wx
import pandas as pd
import numpy as np
import scipy.stats
import math
import matplotlib.pyplot as plt


# 4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
def StatisticalPerformanceDataFunctionForwx(self, event):
    """定义统计成绩数据函数给wx"""

    message = ""
    message_average_max = ""
    message_average_min = ""
    message_std_max = ""
    message_std_mix = ""

    # 在学生成绩数据表格.csv文件中读取学生成绩数据
    student_score_date = pd.read_csv("学生成绩数据.csv", encoding="gbk")

    # 获取班级中各科成绩数据的汇总统计,并写入班级各科成绩数据汇总统计.csv文件
    describe_score_date = student_score_date[["高等数学", "英语", "Python", "Java", "C++"]].describe()
    describe_score_date.index = ["学生人数", "平均分", "标准差", "最低分", "1/4分位数", "中位数(二分之一分位数)", "3/4分位数", "最高分"]
    describe_score_date.to_csv("班级各科成绩数据汇总统计.csv", encoding='gbk', index=True, sep=',')

    # 获取班级中各科平均成绩
    class_average_score_math = describe_score_date.at["平均分", "高等数学"]
    class_average_score_english = describe_score_date.at["平均分", "英语"]
    class_average_score_python = describe_score_date.at["平均分", "Python"]
    class_average_score_java = describe_score_date.at["平均分", "Java"]
    class_average_score_cpp = describe_score_date.at["平均分", "C++"]

    # 获取班级中各科成绩的标准差
    class_std_score_math = describe_score_date.at["标准差", "高等数学"]
    class_std_score_english = describe_score_date.at["标准差", "英语"]
    class_std_score_python = describe_score_date.at["标准差", "Python"]
    class_std_score_java = describe_score_date.at["标准差", "Java"]
    class_std_score_cpp = describe_score_date.at["标准差", "C++"]

    # 获取班级中各科成绩的中位数
    class_median_score_math = describe_score_date.at["中位数(二分之一分位数)", "高等数学"]
    class_median_score_english = describe_score_date.at["中位数(二分之一分位数)", "英语"]
    class_median_score_python = describe_score_date.at["中位数(二分之一分位数)", "Python"]
    class_median_score_java = describe_score_date.at["中位数(二分之一分位数)", "Java"]
    class_median_score_cpp = describe_score_date.at["中位数(二分之一分位数)", "C++"]

    # 查看班级中各科成绩的最高分
    class_max_score_math = describe_score_date.at["最高分", "高等数学"]
    class_max_score_english = describe_score_date.at["最高分", "英语"]
    class_max_score_python = describe_score_date.at["最高分", "Python"]
    class_max_score_java = describe_score_date.at["最高分", "Java"]
    class_max_score_cpp = describe_score_date.at["最高分", "C++"]

    # 获取班级中各科成绩的最低分
    class_min_score_math = describe_score_date.at["最低分", "高等数学"]
    class_min_score_english = describe_score_date.at["最低分", "英语"]
    class_min_score_python = describe_score_date.at["最低分", "Python"]
    class_min_score_java = describe_score_date.at["最低分", "Java"]
    class_min_score_cpp = describe_score_date.at["最低分", "C++"]

    # 获取学生人数
    student_number = student_score_date.shape[0]  # 获取表格的行数

    # 对班级中各学生的成绩数据排序,并写入班级学生成绩排名.csv文件
    rank_student_score_date = student_score_date.sort_values(by="平均分", ascending=False)
    rank_student_score_date["排名"] = range(1, student_number+1)
    rank_student_score_date.to_csv("班级学生成绩排名.csv", encoding='gbk', index=False, sep=',')

    # 进行学生成绩数据分析,分析成绩的平均值
    class_average_score_list = [class_average_score_math, class_average_score_english, class_average_score_python, class_average_score_java, class_average_score_cpp]
    if max(class_average_score_list) == class_average_score_math:
        message_average_max = f"班级中成绩最好的科目是高等数学,其平均分为{class_average_score_math}。"
    elif max(class_average_score_list) == class_average_score_english:
        message_average_max = f"班级中成绩最好的科目是英语,其平均分为{class_average_score_english}。"
    elif max(class_average_score_list) == class_average_score_python:
        message_average_max = f"班级中成绩最好的科目是Python,其平均分为{class_average_score_python}。"
    elif max(class_average_score_list) == class_average_score_java:
        message_average_max = f"班级中成绩最好的科目是Java,其平均分为{class_average_score_java}。"
    elif max(class_average_score_list) == class_average_score_cpp:
        message_average_max = f"班级中成绩最好的科目是C++,其平均分为{class_average_score_cpp}。"

    if min(class_average_score_list) == class_average_score_math:
        message_average_min = f"班级中成绩最差的科目是高等数学,其平均分为{class_average_score_math}。"
    elif min(class_average_score_list) == class_average_score_english:
        message_average_min = f"班级中成绩最差的科目是英语,其平均分为{class_average_score_english}。"
    elif min(class_average_score_list) == class_average_score_python:
        message_average_min = f"班级中成绩最差的科目是Python,其平均分为{class_average_score_python}。"
    elif min(class_average_score_list) == class_average_score_java:
        message_average_min = f"班级中成绩最差的科目是Java,其平均分为{class_average_score_java}。"
    elif min(class_average_score_list) == class_average_score_cpp:
        message_average_min = f"班级中成绩最差的科目是C++,其平均分为{class_average_score_cpp}。"

    # 进行学生成绩数据分析,分析成绩的标准差
    class_std_score_list = [class_std_score_math, class_std_score_english, class_std_score_python, class_std_score_java, class_std_score_cpp]
    if max(class_std_score_list) == class_std_score_math:
        message_std_max = f"班级中成绩稳定性最差的科目是高等数学,其标准差为{class_std_score_math}。"
    elif max(class_std_score_list) == class_std_score_english:
        message_std_max = f"班级中成绩稳定性最差的科目是英语,其标准差为{class_std_score_english}。"
    elif max(class_std_score_list) == class_std_score_python:
        message_std_max = f"班级中成绩稳定性最差的科目是Python,其标准差为{class_std_score_python}。"
    elif max(class_std_score_list) == class_std_score_java:
        message_std_max = f"班级中成绩稳定性最差的科目是Java,其标准差为{class_std_score_java}。"
    elif max(class_std_score_list) == class_std_score_cpp:
        message_std_max = f"班级中成绩稳定性最差的科目是C++,其标准差为{class_std_score_cpp}。"

    if min(class_std_score_list) == class_std_score_math:
        message_std_mix = f"班级中成绩稳定性最好的科目是高等数学,其标准差为{class_std_score_math}。"
    elif min(class_std_score_list) == class_std_score_english:
        message_std_mix = f"班级中成绩稳定性最好的科目是英语,其标准差为{class_std_score_english}。"
    elif min(class_std_score_list) == class_std_score_python:
        message_std_mix = f"班级中成绩稳定性最好的科目是Python,其标准差为{class_std_score_python}。"
    elif min(class_std_score_list) == class_std_score_java:
        message_std_mix = f"班级中成绩稳定性最好的科目是Java,其标准差为{class_std_score_java}。"
    elif min(class_std_score_list) == class_std_score_cpp:
        message_std_mix = f"班级中成绩稳定性最好的科目是C++,其标准差为{class_std_score_cpp}。"

    message = f"本班有{student_number}名同学,对学生成绩数据分析有如下结论:\n1. {message_average_max}\n2. {message_average_min}\n3. {message_std_mix}\n4. {message_std_max}\n\n对学生成绩数据分析的详细结果已保存至程序所在路径。\n文件名:班级各科成绩数据汇总统计.csv\n文件名:班级学生成绩排名.csv"
    wx.MessageBox(message, caption="学生成绩数据分析的结果")  # 弹出提示框

def DrawingStatisticalGraphsFunctionForwx(self, event):
    """定义绘制统计图函数给wx"""

    message = ""

    # 在班级各科成绩数据汇总统计.csv文件中读取成绩统计数据
    describe_score_date = pd.read_csv("班级各科成绩数据汇总统计.csv", encoding="gbk", index_col=0)    # index_col=0:将第一列设为列索引

    # 获取班级中各科平均成绩
    class_average_score_math = describe_score_date.at["平均分", "高等数学"]
    class_average_score_english = describe_score_date.at["平均分", "英语"]
    class_average_score_python = describe_score_date.at["平均分", "Python"]
    class_average_score_java = describe_score_date.at["平均分", "Java"]
    class_average_score_cpp = describe_score_date.at["平均分", "C++"]

    # 计算班级中总的平均成绩
    class_average_score = (class_average_score_math+class_average_score_english+class_average_score_python+class_average_score_java+class_average_score_cpp) / 5

    # 获取班级中各科成绩的标准差
    class_std_score_math = describe_score_date.at["标准差", "高等数学"]
    class_std_score_english = describe_score_date.at["标准差", "英语"]
    class_std_score_python = describe_score_date.at["标准差", "Python"]
    class_std_score_java = describe_score_date.at["标准差", "Java"]
    class_std_score_cpp = describe_score_date.at["标准差", "C++"]

    # 计算班级中总的平均标准差
    class_std_score = (class_std_score_math+class_std_score_english+class_std_score_python+class_std_score_java+class_std_score_cpp) / 5

    def NormalDistribution(x, mu=50, sigma=5):
        """此函数返回正态分布的概率密度函数,x:输入待计算的值,μ:(mu)为期望,σ:(sigma为标准差"""

        # 0.3989422804014327 = 1.0 / math.sqrt(2 * math.pi),exp()函数返回x的指数:e^x。
        return 0.3989422804014327 / sigma * (math.exp(- (x - mu) * (x - mu) / (2 * sigma * sigma)))

    # 支持中文
    plt.rcParams["font.sans-serif"] = ["SimHei"]  # 用来正常显示中文标签
    plt.rcParams["axes.unicode_minus"] = False  # 用来正常显示负号

    # 设置mu和sigma
    mu = class_average_score
    sigma = class_std_score

    # 绘制正态分布曲线
    x_axis = []  # 横坐标
    for x in range(101):
        x_axis.append(x)

    y_axis = []  # 纵坐标
    for x in x_axis:
        y_axis.append(NormalDistribution(x, mu, sigma))

    plt.plot(x_axis, y_axis, color="black")

    # 填充正态分布曲线
    for i in range(1, 4):
        x_axis = np.linspace(mu - sigma * i, mu + sigma * i, 100)
        y_axis = scipy.stats.norm.pdf(x_axis, mu, sigma)

        plt.fill_between(x_axis, y_axis, 0, alpha=0.3, color="orange")

    # 绘制线条和文字
    percents = ["68.26%", "95.45%", "99.73%"]
    for i in range(1, 4):
        # 计算中间三个区间连线的两端坐标
        x1 = mu - sigma * i
        x2 = mu + sigma * i
        y1 = NormalDistribution(x1, mu, sigma)
        y2 = NormalDistribution(x2, mu, sigma)
        # 绘制三条线段,分别为左右1条和上下2条
        plt.plot([x1, x2], [y1, y2], color="black")
        plt.plot([x1, x1], [y1, 0], color="black")
        plt.plot([x2, x2], [y1, 0], color="black")
        # 绘制相应的文本
        plt.text(x1 - 12, y1, f"$\mu - {i}\sigma$", fontsize=14)
        plt.text(x2 + 3, y1, f"$\mu + {i}\sigma$", fontsize=14)
        plt.text((x1 + x2) / 2 - 2, y1, percents[i - 1], fontsize=14, color="black")

    # 绘制最上方的单个的mu
    plt.text(mu, NormalDistribution(mu, mu, sigma) + 0.0003, f"$\mu$", fontsize=14, color="black")

    # 设置图表标题和标题字号
    plt.title(f"班级综合成绩正态分布($\mu={'%0.1f' %mu}, \sigma={'%0.1f' %sigma}$)", fontsize=22)

    # 设置刻度的字号
    plt.tick_params(axis="both", which="major", labelsize=14)

    # 设置x,y轴标签及其字号
    plt.xlabel("分数", fontsize=14)
    plt.ylabel("分数概率", fontsize=14)

    # 设置X轴的边为0至100
    plt.xlim(0, 100)

    # 设置X轴的显示的内容为 [0, 10, 20, ..., 100]
    plt.xticks(range(0, 110, 10))

    # 设置背景网格
    plt.grid(color="black", alpha=0.2)

    # 保存绘制的图片
    plt.savefig("班级综合成绩正态分布曲线.png")

    # 显示绘制的图片
    plt.show()

    message = f"已绘制且已打开班级综合成绩正态分布曲线。\n\n班级综合成绩正态分布曲线的图片已保存至程序所在路径。\n文件名:班级综合成绩正态分布曲线.csv"
    wx.MessageBox(message, caption="班级综合成绩正态分布曲线的绘制结果")  # 弹出提示框

    # 用操作系统显示绘制的图片
    os.startfile("班级综合成绩正态分布曲线.png")  # 用操作系统打开图片
  1. 提高程序健壮性_代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理

"""
# 5.提高程序健壮性:自定义异常类和异常处理
class NumericalRangeError(Exception):
    """当输入0~100以外的数字时引发该异常"""
    pass

四、交流学习

互联网开源精神需要大家一起互相交流学习,互相支持奉献。欢迎大家与我友好交流。

加我 QQ 好友获取所有项目源码和项目文档,感谢大家的支持!

Python 程序设计项目 成绩信息管理系统 大学编程作业(TUST 天津科技大学 2021 年)

一、项目简介

本成绩信息管理系统 ,我使用了 Python 丰富的第三方开源模块,如 csv、wxPython、pandas、numpy、scipy、math、matplotlib、PyInstaller 等来制作,实现了简单的增删查改逻辑,实现了成绩信息数据的简单统计分析和 csv 文件自动的存储,并且 UI 界面较为美观易用。通过这次 Python 程序设计项目的实践,我巩固了 Python 的语法知识,熟练应用了各个第三方开源模块,为之后的数学建模学习打下基础。

这个项目是我大二写的,现在回顾已经非常粗糙,分享出来一方面希望可以帮助初学者,另一方面希望能让同学们可以从目前大学中普遍毫无价值的形式主义作业中解脱出来,更加高效地学习优质计算机知识和主流编程技术,一起发扬开源精神,感受互联网技术的美好愿景。

二、项目要求

  1. 注册账号功能
    注册账号,并保存为用户名和密码.csv 文件。

  2. 登录账号功能
    登录账号,打开主界面。

  3. 取消登录功能
    取消登录,关闭登录界面。

  4. 录入成绩功能
    录入成绩,手动计算或自动计算总分和平均分,并保存为学生成绩数据.csv 文件。

  5. 查询成绩功能
    查询成绩,打开消息对话框显示结果。

  6. 修改成绩功能

  7. 删除成绩功能

  8. 统计成绩数据功能
    分析学习成绩数据,打开消息对话框显示结果,并保存为班级各科成绩数据汇总统计.csv 文件和班级学生成绩排名.csv 文件。

  9. 绘制成绩统计图功能
    绘制班级综合成绩正态分布曲线,打开消息对话框显示结果,并保存为班级综合成绩正态分布曲线.png 文件。

  10. 异常处理功能
    录入成绩时,输入非数字字符弹出对话框提示“请在成绩栏中输入数字!”,输入 0 到 100 以外的数字弹出对话框提示“请在成绩栏中输入 0~100 以内的数字!”。

  11. 数据存储位置说明
    程序运行时的数据将保存在程序运行时所在路径。

三、项目源码

程序设计思路:

  1. 用户数据和学生成绩数据的类
  2. 图形用户界面:wxPython 模块
  3. 功能实现函数:调用用户数据和学生成绩数据的类中的方法
  4. 统计数据,绘制统计图的函数:pandas 模块,matplotlib 模块
  5. 提高程序健壮性:自定义异常类和异常处理

源代码:

  1. Python 综合实验成绩信息管理系统主代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理
"""
import 图形用户界面_代码文件 as MyModule2


if __name__ == "__main__":
    score_management_app = MyModule2.wx.App()  # 初始化App
    login_interface_frame = MyModule2.LoginInterfaceFrame(parent=None, id=MyModule2.wx.ID_ANY)  # 实例LoginInterfaceFrame类,并传递参数
    login_interface_frame.Show(True)  # 显示登录窗口
    score_management_app.MainLoop()  # 调用主循环方法
  1. 用户数据和学生成绩数据的类_代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理

"""
import os
import csv


# 1.用户数据和学生成绩数据的类
class UserDate:
    """定义用户数据类"""

    def __init__(self, username="", password=""):
        """初始化属性"""
        self.username = username
        self.password = password

    def RegisterFunction(self):
        """定义注册函数"""

        result = ""

        # 判断用户名和密码.csv文件是否存在,并且在用户数据表格csv文件中初始化表头为用户名和密码
        if os.path.exists("用户名和密码.csv") is False:
            with open("用户名和密码.csv", mode="a", newline="") as user_date_csv:
                w = csv.writer(user_date_csv)
                w.writerow(["用户名", "密码"])

        # 判断用户名和密码是否输入
        if self.username == "" or self.password == "":
            result = "用户名和密码不能为空!"
        else:
            # 判断用户名是否已注册
            user_is_registered = False

            with open("用户名和密码.csv", mode="r") as user_date_csv:
                r = csv.reader(user_date_csv)
                for line_list in r:
                    if line_list != ["用户名", "密码"]:  # 用来避免第一行表头的对判断的影响
                        if self.username == line_list[0]:  # 用列表line_list的下标来获取一行中的用户名
                            user_is_registered = True
                            result = "此用户名已被注册,请重新输入用户名!"

            # 在用户数据表格csv文件中写入用户名和密码
            if user_is_registered is False:
                with open("用户名和密码.csv", mode="a", newline="") as user_date_csv:
                    w = csv.writer(user_date_csv)
                    w.writerow([self.username, self.password])
                    result = f"用户“{self.username}”注册成功!"

        return result

    def LoginFunction(self):
        """定义登录函数"""

        result = ""

        # 判断用户名和密码是否输入
        if self.username == "" or self.password == "":
            result = "用户名和密码不能为空!"
        else:
            # 判断用户名和密码.csv文件是否存在,提示用户先注册
            if os.path.exists("用户名和密码.csv") is False:
                result = "请先注册账户!"
            else:
                result = "用户名或密码错误!"
                # 在用户数据表格csv文件中查询比较用户名和密码是否一致
                with open("用户名和密码.csv", mode="r") as user_date_csv:
                    r = csv.reader(user_date_csv)
                    for line_list in r:
                        if line_list != ["用户名", "密码"]:  # 用来避免第一行表头的对判断的影响
                            if self.username == line_list[0]:  # 用列表line_list的下标来获取一行中的用户名和密码
                                if self.password == line_list[1]:
                                    result = "登录成功!"

        return result


class StudentDate:
    """定义学生数据类"""

    def __init__(self, name="", id="", score_math=0.0, score_english=0.0, score_python=0.0, score_java=0.0, score_cpp=0.0, total_score=0.0, average_score=0.0):
        """初始化属性"""
        self.name = name
        self.id = id
        self.score_math = score_math
        self.score_english = score_english
        self.score_python = score_python
        self.score_java = score_java
        self.score_cpp = score_cpp
        self.total_score = total_score
        self.average_score = average_score

    def SaveScoreFunction(self):
        """定义保存成绩函数"""

        result = ""

        # 判断学生成绩数据.csv文件是否存在,并且在用户数据表格csv文件中初始化表头为姓名,学号,高等数学,英语,Python,Java,C++,总分,平均分。
        if os.path.exists("学生成绩数据.csv") is False:
            with open("学生成绩数据.csv", mode="a", newline="") as student_score_date_csv:
                w = csv.writer(student_score_date_csv)
                w.writerow(["姓名", "学号", "高等数学", "英语", "Python", "Java", "C++", "总分", "平均分"])

        # 判断学生姓名,学号是否输入
        if self.name == "" or self.id == "":
            result = "请输入姓名和学号!"
        else:
            # 判断学号是否重复
            student_score_is_repeated = False

            with open("学生成绩数据.csv", mode="r") as student_score_date_csv:
                r = csv.reader(student_score_date_csv)
                for line_list in r:
                    if line_list != ["姓名", "学号", "高等数学", "英语", "Python", "Java", "C++", "总分", "平均分"]:  # 用来避免第一行表头的对判断的影响
                        if self.id == line_list[1]:  # 用列表line_list的下标来获取一行中的学号
                            student_score_is_repeated = True
                            result = f"学号{self.id}已重复,无法保存学生成绩,请检查学号是否正确!"

            # 在学生成绩数据表格csv文件中写入学生成绩
            if student_score_is_repeated is False:
                with open("学生成绩数据.csv", mode="a", newline="") as student_score_date_csv:
                    w = csv.writer(student_score_date_csv)
                    w.writerow([self.name, self.id, self.score_math, self.score_english, self.score_python, self.score_java, self.score_cpp, self.total_score, self.average_score])
                    result = f"学号为{self.id}的学生成绩已保存!\n\n学生成绩数据已保存至程序所在路径。\n文件名:学生成绩数据.csv"

        return result

    def FindScoreFunction(self):
        """定义查找成绩函数"""

        result = ""

        # 判断学号是否输入
        if self.id == "":
            result = "请输入要查询的学号!"
        else:
            # 判断学生成绩数据.csv文件是否存在,提示用户先录入成绩
            if os.path.exists("学生成绩数据.csv") is False:
                result = "请先录入成绩!"
            else:
                result = "未找到此学生的成绩信息!"
                # 在学生成绩数据表格csv文件中查询比较学号是否相一致
                with open("学生成绩数据.csv", mode="r") as student_score_date_csv:
                    r = csv.reader(student_score_date_csv)
                    for line_list in r:
                        if line_list != ["姓名", "学号", "高等数学", "英语", "Python", "Java", "C++", "总分", "平均分"]:  # 用来避免第一行表头的对判断的影响
                            if self.id == line_list[1]:  # 用列表line_list的下标来获取一行中的学号
                                # 找到此学生的成绩信息后,用列表line_list的下标来获取相对应的学生成绩数据
                                self.name = line_list[0]
                                self.id = line_list[1]
                                self.score_math = line_list[2]
                                self.score_english = line_list[3]
                                self.score_python = line_list[4]
                                self.score_java = line_list[5]
                                self.score_cpp = line_list[6]
                                self.total_score = line_list[7]
                                self.average_score = line_list[8]
                                result = f"已找到此学生的成绩信息!\n\n姓名:{self.name}\n学号:{self.id}\n高等数学:{self.score_math}\n英语:{self.score_english}\nPython:{self.score_python}\nJava:{self.score_java}\nC++:{self.score_cpp}\n总分:{self.total_score}\n平均分:{self.average_score}"

        return result

    def ReviseScoreFunction(self):
        """定义修改成绩函数"""
        return True

    def DeleteScoreFunction(self):
        """定义删除成绩函数"""
        return True
  1. 图形用户界面_代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理

"""
import wx
import 功能实现函数_代码文件 as MyModule3
import 统计数据_绘制统计图的函数_代码文件 as MyModule4


# 2.图形用户界面:wxPython模块
class LoginInterfaceFrame(wx.Frame):
    """定义登录界面的Frame框架类"""

    def __init__(self, parent, id):
        # 初始化Frame框架
        wx.Frame.__init__(self, parent, id, title="用户登录界面 - 成绩信息管理系统", size=(720, 480))

        # 定义登录界面的Panel面板
        login_interface_panel = wx.Panel(self)

        # 创建登录界面的文本
        self.login_title_1 = wx.StaticText(login_interface_panel, label="请输入用户名和密码")
        self.login_title_2 = wx.StaticText(login_interface_panel, label="欢迎使用成绩信息管理系统\n作者:MYXHcode")
        self.label_user = wx.StaticText(login_interface_panel, label="用户名:")
        self.text_user = wx.TextCtrl(login_interface_panel, style=wx.TE_LEFT)
        self.label_pwd = wx.StaticText(login_interface_panel, label="密    码:")
        self.text_pwd = wx.TextCtrl(login_interface_panel, style=wx.TE_PASSWORD)

        # 创建按钮,并绑定事件
        self.button_register = wx.Button(login_interface_panel, label="注册")
        self.button_register.Bind(wx.EVT_BUTTON, self.OncLickRegister)
        self.button_login = wx.Button(login_interface_panel, label="登录")
        self.button_login.Bind(wx.EVT_BUTTON, self.OncLickLogin)
        self.button_cancel = wx.Button(login_interface_panel, label="取消")
        self.button_cancel.Bind(wx.EVT_BUTTON, self.OncLickCancel)

        # 添加容器,容器中控件按纵向并排排列
        vsizer_user = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_user.Add(self.label_user, proportion=0, flag=wx.ALL, border=5)
        vsizer_user.Add(self.text_user, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        vsizer_pwd = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_pwd.Add(self.label_pwd, proportion=0, flag=wx.ALL, border=5)
        vsizer_pwd.Add(self.text_pwd, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        # 添加容器,容器中控件按横向并排排列
        hsizer_button = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_button.Add(self.button_register, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        hsizer_button.Add(self.button_login, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        hsizer_button.Add(self.button_cancel, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all.Add(self.login_title_1, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=15)
        vsizer_all.Add(vsizer_user, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=65)
        vsizer_all.Add(vsizer_pwd, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=65)
        vsizer_all.Add(hsizer_button, proportion=0, flag=wx.ALIGN_CENTER | wx.TOP, border=25)
        vsizer_all.Add(self.login_title_2, proportion=20, flag=wx.BOTTOM | wx.TOP | wx.LEFT, border=15)
        login_interface_panel.SetSizer(vsizer_all)

    # 定义按钮函数
    def OncLickRegister(self, event):
        """点击按钮,执行方法"""
        MyModule3.RegisterFunctionForwx(self, event)

    def OncLickLogin(self, event):
        """点击按钮,执行方法"""
        MyModule3.LoginFunctionForwx(self, event)

    def OncLickCancel(self, event):
        """点击按钮,执行方法"""
        MyModule3.CancelLoginFunctionForwx(self, event)


class MainFrame(wx.Frame):
    """定义主界面的Frame框架类"""

    def __init__(self, parent, id):
        # 初始化Frame框架
        wx.Frame.__init__(self, parent, id, "主界面 - 成绩信息管理系统", size=(720, 480))

        # 定义主界面的Panel面板
        main_panel = wx.Panel(self)

        # 创建主界面的文本
        self.main_title_1 = wx.StaticText(main_panel, label="欢迎使用成绩信息管理系统")
        self.main_title_2 = wx.StaticText(main_panel, label="请选择下列功能:")
        self.main_title_3 = wx.StaticText(main_panel, label="\t成绩记录:")
        self.main_title_4 = wx.StaticText(main_panel, label="\t成绩统计:")
        self.main_title_5 = wx.StaticText(main_panel, label="作者:MYXHcode")

        # 创建按钮,并绑定事件
        self.button_score_entry = wx.Button(main_panel, label="成绩录入")
        self.button_score_entry.Bind(wx.EVT_BUTTON, self.OncLickScoreEntry)
        self.button_score_find = wx.Button(main_panel, label="成绩查询")
        self.button_score_find.Bind(wx.EVT_BUTTON, self.OncLickScoreFind)
        self.button_score_revise = wx.Button(main_panel, label="成绩修改")
        self.button_score_revise.Bind(wx.EVT_BUTTON, self.OncLickScoreRevise)
        self.button_score_delete = wx.Button(main_panel, label="成绩删除")
        self.button_score_delete.Bind(wx.EVT_BUTTON, self.OncLickScoreDelete)
        self.button_score_statistics = wx.Button(main_panel, label="统计成绩数据")
        self.button_score_statistics.Bind(wx.EVT_BUTTON, self.OncLickStatistics)
        self.button_score_summary_graph = wx.Button(main_panel, label="绘制成绩统计图")
        self.button_score_summary_graph.Bind(wx.EVT_BUTTON, self.OncLickScoreSummaryGraph)

        # 添加容器,容器中控件按纵向并排排列
        vsizer_button_score = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_button_score.Add(self.button_score_entry, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        vsizer_button_score.Add(self.button_score_find, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        vsizer_button_score.Add(self.button_score_revise, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        vsizer_button_score.Add(self.button_score_delete, proportion=1, flag=wx.ALIGN_CENTER, border=5)
        # 添加容器,容器中控件按横向并排排列
        hsizer_button_statistics = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_button_statistics.Add(self.button_score_statistics, proportion=0, flag=wx.ALIGN_CENTER, border=5)
        hsizer_button_statistics.Add(self.button_score_summary_graph, proportion=0, flag=wx.ALIGN_CENTER, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all.Add(self.main_title_1, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=15)
        vsizer_all.Add(self.main_title_2, proportion=0, flag=wx.BOTTOM | wx.LEFT | wx.RIGHT, border=15)
        vsizer_all.Add(self.main_title_3, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=65)
        vsizer_all.Add(vsizer_button_score, proportion=0, flag=wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all.Add(self.main_title_4, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=65)
        vsizer_all.Add(hsizer_button_statistics, proportion=0, flag=wx.ALIGN_CENTER | wx.BOTTOM, border=45)
        vsizer_all.Add(self.main_title_5, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.LEFT, border=15)
        main_panel.SetSizer(vsizer_all)

    # 定义按钮函数
    def OncLickScoreEntry(self, event):
        """点击按钮,执行方法"""
        score_entry_frame = ScoreEntryFrame(parent=None, id=wx.ID_ANY)  # 实例ScoreEntryFrame类,并传递参数
        score_entry_frame.Show(True)  # 显示窗口

    def OncLickScoreFind(self, event):
        """点击按钮,执行方法"""
        score_find_frame = ScoreFindFrame(parent=None, id=wx.ID_ANY)  # 实例ScoreFindFrame类,并传递参数
        score_find_frame.Show(True)  # 显示窗口

    def OncLickScoreRevise(self, event):
        """点击按钮,执行方法"""
        return True

    def OncLickScoreDelete(self, event):
        """点击按钮,执行方法"""
        return True

    def OncLickStatistics(self, event):
        """点击按钮,执行方法"""
        MyModule4.StatisticalPerformanceDataFunctionForwx(self, event)

    def OncLickScoreSummaryGraph(self, event):
        """点击按钮,执行方法"""
        MyModule4.DrawingStatisticalGraphsFunctionForwx(self, event)


class ScoreEntryFrame(wx.Frame):
    """定义成绩录入界面的Frame框架类"""

    def __init__(self, parent, id):
        # 初始化Frame框架
        wx.Frame.__init__(self, parent, id, "成绩录入界面 - 成绩信息管理系统", size=(900, 600))

        # 定义成绩录入界面的Panel面板
        score_entry_panel = wx.Panel(self)

        # 定义成绩录入界面的文本
        self.score_entry_title_1 = wx.StaticText(score_entry_panel, label="成绩录入功能")
        self.score_entry_title_2 = wx.StaticText(score_entry_panel, label="请输入你的姓名:")
        self.score_entry_title_3 = wx.StaticText(score_entry_panel, label="请输入你的学号:")
        self.score_entry_title_4 = wx.StaticText(score_entry_panel, label="请输入你的各科成绩:")
        self.score_entry_title_5 = wx.StaticText(score_entry_panel, label="作者:MYXHcode")
        self.label_name = wx.StaticText(score_entry_panel, label="姓名:")
        self.text_name = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_id = wx.StaticText(score_entry_panel, label="学号:")
        self.text_id = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_score_math = wx.StaticText(score_entry_panel, label="高等数学:")
        self.text_score_math = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_score_english = wx.StaticText(score_entry_panel, label="英   语:")
        self.text_score_english = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_score_python = wx.StaticText(score_entry_panel, label="Python:")
        self.text_score_python = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_score_java = wx.StaticText(score_entry_panel, label="J a v a:")
        self.text_score_java = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_score_cpp = wx.StaticText(score_entry_panel, label="C + +:")
        self.text_score_cpp = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_total_score = wx.StaticText(score_entry_panel, label="总   分:")
        self.text_total_score = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)
        self.label_average_score = wx.StaticText(score_entry_panel, label="平均分:")
        self.text_average_score = wx.TextCtrl(score_entry_panel, style=wx.TE_LEFT)

        # 创建按钮,并绑定事件
        self.button_total_score = wx.Button(score_entry_panel, label="计算总分")
        self.button_total_score.Bind(wx.EVT_BUTTON, self.OncLickTotalScore)
        self.button_average_score = wx.Button(score_entry_panel, label="计算平均分")
        self.button_average_score.Bind(wx.EVT_BUTTON, self.OncLickAverageScore)
        self.button_save = wx.Button(score_entry_panel, label="保存成绩")
        self.button_save.Bind(wx.EVT_BUTTON, self.OncLickSaveScore)

        # 添加容器,容器中控件按横向并排排列
        hsizer_name = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_name.Add(self.label_name, proportion=0, flag=wx.ALL, border=5)
        hsizer_name.Add(self.text_name, proportion=1, flag=wx.ALL, border=5)
        hsizer_id = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_id.Add(self.label_id, proportion=0, flag=wx.ALL, border=5)
        hsizer_id.Add(self.text_id, proportion=1, flag=wx.ALL, border=5)
        hsizer_score_math = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_score_math.Add(self.label_score_math, proportion=0, flag=wx.ALL, border=5)
        hsizer_score_math.Add(self.text_score_math, proportion=1, flag=wx.ALL, border=5)
        hsizer_score_english = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_score_english.Add(self.label_score_english, proportion=0, flag=wx.ALL, border=5)
        hsizer_score_english.Add(self.text_score_english, proportion=1, flag=wx.ALL, border=5)
        hsizer_score_python = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_score_python.Add(self.label_score_python, proportion=0, flag=wx.ALL, border=5)
        hsizer_score_python.Add(self.text_score_python, proportion=1, flag=wx.ALL, border=5)
        hsizer_score_java = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_score_java.Add(self.label_score_java, proportion=0, flag=wx.ALL, border=5)
        hsizer_score_java.Add(self.text_score_java, proportion=1, flag=wx.ALL, border=5)
        hsizer_score_cpp = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_score_cpp.Add(self.label_score_cpp, proportion=0, flag=wx.ALL, border=5)
        hsizer_score_cpp.Add(self.text_score_cpp, proportion=1, flag=wx.ALL, border=5)
        hsizer_total_score = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_total_score.Add(self.label_total_score, proportion=0, flag=wx.ALL, border=5)
        hsizer_total_score.Add(self.text_total_score, proportion=1, flag=wx.ALL, border=5)
        hsizer_average_score = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_average_score.Add(self.label_average_score, proportion=0, flag=wx.ALL, border=5)
        hsizer_average_score.Add(self.text_average_score, proportion=1, flag=wx.ALL, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_button = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_button.Add(self.button_total_score, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5)
        vsizer_button.Add(self.button_average_score, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5)
        vsizer_button.Add(self.button_save, proportion=0, flag=wx.LEFT, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all_left = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all_left.Add(self.score_entry_title_2, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15)
        vsizer_all_left.Add(hsizer_name, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(self.score_entry_title_3, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15)
        vsizer_all_left.Add(hsizer_id, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(self.score_entry_title_4, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15)
        vsizer_all_left.Add(hsizer_score_math, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_score_english, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_score_python, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_score_java, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_score_cpp, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_total_score, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all_left.Add(hsizer_average_score, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all_right = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all_right.Add(vsizer_button, proportion=0, flag=wx.ALIGN_CENTER | wx.TOP, border=15)
        # 添加容器,容器中控件按横向并排排列
        hsizer_all_middle = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_all_middle.Add(vsizer_all_left, proportion=0, flag=wx.ALIGN_CENTER, border=20)
        hsizer_all_middle.Add(vsizer_all_right, proportion=0, flag=wx.ALIGN_CENTER, border=20)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all.Add(self.score_entry_title_1, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=20)
        vsizer_all.Add(hsizer_all_middle, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=20)
        vsizer_all.Add(self.score_entry_title_5, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.LEFT, border=15)
        score_entry_panel.SetSizer(vsizer_all)

    # 定义按钮函数
    def OncLickTotalScore(self, event):
        """点击按钮,执行方法"""
        MyModule3.TotalScoreForwx(self, event)

    def OncLickAverageScore(self, event):
        """点击按钮,执行方法"""
        MyModule3.AverageScoreForwx(self, event)

    def OncLickSaveScore(self, event):
        """点击按钮,执行方法"""
        MyModule3.SaveScoreFunctionForwx(self, event)


class ScoreFindFrame(wx.Frame):
    """定义成绩查询界面的Frame框架类"""

    def __init__(self, parent, id):
        # 初始化Frame框架
        wx.Frame.__init__(self, parent, id, "成绩查询界面 - 成绩信息管理系统", size=(720, 480))

        # 定义成绩查询界面的Panel面板
        score_find_panel = wx.Panel(self)

        # 定义成绩查询界面的文本
        self.score_find_title_1 = wx.StaticText(score_find_panel, label="成绩查询功能")
        self.score_find_title_2 = wx.StaticText(score_find_panel, label="请输入要查询的学号:")
        self.score_find_title_3 = wx.StaticText(score_find_panel, label="作者:MYXHcode")
        self.label_id = wx.StaticText(score_find_panel, label="学号:")
        self.text_id = wx.TextCtrl(score_find_panel, style=wx.TE_LEFT)

        # 创建按钮,并绑定事件
        self.button_find = wx.Button(score_find_panel, label="查询成绩")
        self.button_find.Bind(wx.EVT_BUTTON, self.OncLickFindScore)

        # 添加容器,容器中控件按横向并排排列
        hsizer_id = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_id.Add(self.label_id, proportion=0, flag=wx.ALL, border=5)
        hsizer_id.Add(self.text_id, proportion=1, flag=wx.ALL, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_button = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_button.Add(self.button_find, proportion=0, flag=wx.LEFT, border=5)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all_left = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all_left.Add(self.score_find_title_2, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15)
        vsizer_all_left.Add(hsizer_id, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all_right = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all_right.Add(vsizer_button, proportion=0, flag=wx.ALIGN_CENTER | wx.TOP, border=15)
        # 添加容器,容器中控件按横向并排排列
        hsizer_all_middle = wx.BoxSizer(orient=wx.HORIZONTAL)
        hsizer_all_middle.Add(vsizer_all_left, proportion=0, flag=wx.ALIGN_CENTER, border=20)
        hsizer_all_middle.Add(vsizer_all_right, proportion=0, flag=wx.ALIGN_CENTER, border=20)
        # 添加容器,容器中控件按纵向并排排列
        vsizer_all = wx.BoxSizer(orient=wx.VERTICAL)
        vsizer_all.Add(self.score_find_title_1, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=20)
        vsizer_all.Add(hsizer_all_middle, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=20)
        vsizer_all.Add(self.score_find_title_3, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.LEFT, border=15)
        score_find_panel.SetSizer(vsizer_all)

    # 定义按钮函数
    def OncLickFindScore(self, event):
        """点击按钮,执行方法"""
        MyModule3.FindScoreFunctionForwx(self, event)
  1. 功能实现函数_代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理

"""
import wx
import 用户数据和学生成绩数据的类_代码文件 as MyModule1
import 图形用户界面_代码文件 as MyModule2
import 提高程序健壮性_代码文件 as MyModule5


# 3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
def RegisterFunctionForwx(self, event):
    """定义注册函数给wx"""

    username = self.text_user.GetValue()  # 获取输入的用户名
    password = self.text_pwd.GetValue()  # 获取输入的密码

    user_date = MyModule1.UserDate(username, password)  # 实例化UserDate类
    message = user_date.RegisterFunction()  # 调用注册函数

    wx.MessageBox(message, caption="注册提示")  # 弹出提示框


def LoginFunctionForwx(self, event):
    """定义登录函数给wx"""

    username = self.text_user.GetValue()  # 获取输入的用户名
    password = self.text_pwd.GetValue()  # 获取输入的密码

    user_date = MyModule1.UserDate(username, password)  # 实例化UserDate类
    message = user_date.LoginFunction()  # 调用登录函数

    if message == "登录成功!":
        wx.MessageBox(message, caption="登录提示")  # 弹出提示框
        MyModule2.LoginInterfaceFrame.Close(self)  # 关闭登录窗口
        main_frame = MyModule2.MainFrame(parent=None, id=wx.ID_ANY)  # 实例MainFrame类,并传递参数
        main_frame.Show(True)  # 显示主窗口
    else:
        wx.MessageBox(message, caption="登录提示")  # 弹出提示框


def CancelLoginFunctionForwx(self, event):
    """定义取消登录函数给wx"""
    self.text_user.SetValue("")  # 清空输入的用户名
    self.text_pwd.SetValue("")  # 清空输入的密码
    MyModule2.LoginInterfaceFrame.Close(self)  # 关闭登录窗口


def TotalScoreForwx(self, event):
    """定义计算总分函数给wx"""

    try:
        # 当输入非数字时引发异常
        score_math = float(self.text_score_math.GetValue())  # 获取输入的高等数学成绩
        score_english = float(self.text_score_english.GetValue())  # 获取输入的英语成绩
        score_python = float(self.text_score_python.GetValue())  # 获取输入的Python成绩
        score_java = float(self.text_score_java.GetValue())  # 获取输入的Java成绩
        score_cpp = float(self.text_score_cpp.GetValue())  # 获取输入的C++成绩

        # 当输入0~100以外的数字时引发异常
        if score_math < 0 or score_math > 100:
            raise MyModule5.NumericalRangeError
        elif score_english < 0 or score_english > 100:
            raise MyModule5.NumericalRangeError
        elif score_python < 0 or score_python > 100:
            raise MyModule5.NumericalRangeError
        elif score_java < 0 or score_java > 100:
            raise MyModule5.NumericalRangeError
        elif score_cpp < 0 or score_cpp > 100:
            raise MyModule5.NumericalRangeError

        # 计算总分,并输入到总分栏
        total_score = (score_math + score_english + score_python + score_java + score_cpp)
        self.text_total_score.SetValue(f"{total_score}")
    except ValueError:  # 捕获异常
        message = "请在成绩栏中输入数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框
    except MyModule5.NumericalRangeError:  # 捕获异常
        message = "请在成绩栏中输入0~100以内的数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框


def AverageScoreForwx(self, event):
    """定义计算平均分函数给wx"""

    try:
        # 当输入非数字时引发异常
        score_math = float(self.text_score_math.GetValue())  # 获取输入的高等数学成绩
        score_english = float(self.text_score_english.GetValue())  # 获取输入的英语成绩
        score_python = float(self.text_score_python.GetValue())  # 获取输入的Python成绩
        score_java = float(self.text_score_java.GetValue())  # 获取输入的Java成绩
        score_cpp = float(self.text_score_cpp.GetValue())  # 获取输入的C++成绩

        # 当输入0~100以外的数字时引发异常
        if score_math < 0 or score_math > 100:
            raise MyModule5.NumericalRangeError
        elif score_english < 0 or score_english > 100:
            raise MyModule5.NumericalRangeError
        elif score_python < 0 or score_python > 100:
            raise MyModule5.NumericalRangeError
        elif score_java < 0 or score_java > 100:
            raise MyModule5.NumericalRangeError
        elif score_cpp < 0 or score_cpp > 100:
            raise MyModule5.NumericalRangeError

        # 计算平均分,并输入到平均分栏
        total_score = (score_math + score_english + score_python + score_java + score_cpp)
        average_score = (total_score / 5)
        self.text_average_score.SetValue(f"{average_score}")
    except ValueError:  # 捕获异常
        message = "请在成绩栏中输入数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框
    except MyModule5.NumericalRangeError:  # 捕获异常
        message = "请在成绩栏中输入0~100以内的数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框


def SaveScoreFunctionForwx(self, event):
    """定义保存成绩函数给wx"""

    name = self.text_name.GetValue()  # 获取输入的姓名
    id = self.text_id.GetValue()  # 获取输入的学号

    try:
        # 当输入非数字时引发异常
        score_math = float(self.text_score_math.GetValue())  # 获取输入的高等数学成绩
        score_english = float(self.text_score_english.GetValue())  # 获取输入的英语成绩
        score_python = float(self.text_score_python.GetValue())  # 获取输入的Python成绩
        score_java = float(self.text_score_java.GetValue())  # 获取输入的Java成绩
        score_cpp = float(self.text_score_cpp.GetValue())  # 获取输入的C++成绩
        total_score = self.text_total_score.GetValue()  # 获取输入的总分
        average_score = self.text_average_score.GetValue()  # 获取输入的平均分

        # 当输入0~100以外的数字时引发异常
        if score_math < 0 or score_math > 100:
            raise MyModule5.NumericalRangeError
        elif score_english < 0 or score_english > 100:
            raise MyModule5.NumericalRangeError
        elif score_python < 0 or score_python > 100:
            raise MyModule5.NumericalRangeError
        elif score_java < 0 or score_java > 100:
            raise MyModule5.NumericalRangeError
        elif score_cpp < 0 or score_cpp > 100:
            raise MyModule5.NumericalRangeError

        # 自动计算总分和平均分
        total_score_auto = (score_math + score_english + score_python + score_java + score_cpp)
        average_score_auto = (total_score_auto / 5)

        # 改正用户输入错误的总分和平均分
        if total_score != total_score_auto or average_score != average_score_auto:
            total_score = total_score_auto
            average_score = average_score_auto
            self.text_total_score.SetValue(f"{total_score}")
            self.text_average_score.SetValue(f"{average_score}")

        student_date = MyModule1.StudentDate(name, id, score_math, score_english, score_python, score_java, score_cpp, total_score, average_score)  # 实例化StudentDate类
        message = student_date.SaveScoreFunction()  # 调用保存成绩函数
        wx.MessageBox(message, caption="成绩录入结果")  # 弹出提示框
    except ValueError:  # 捕获异常
        message = "请在成绩栏中输入数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框
    except MyModule5.NumericalRangeError:  # 捕获异常
        message = "请在成绩栏中输入0~100以内的数字!"
        wx.MessageBox(message, caption="提示")  # 弹出提示框


def FindScoreFunctionForwx(self, event):
    """定义查询成绩函数给wx"""

    id = self.text_id.GetValue()  # 获取输入的学号

    student_date = MyModule1.StudentDate(id=id)  # 实例化StudentDate类
    message = student_date.FindScoreFunction()  # 调用查询成绩函数

    if message == "请输入要查询的学号!":
        wx.MessageBox(message, caption="提示")  # 弹出提示框
    else:
        wx.MessageBox(message, caption="成绩查询结果")  # 弹出提示框
  1. 统计数据绘制统计图的函数代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理

"""
import os
import wx
import pandas as pd
import numpy as np
import scipy.stats
import math
import matplotlib.pyplot as plt


# 4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
def StatisticalPerformanceDataFunctionForwx(self, event):
    """定义统计成绩数据函数给wx"""

    message = ""
    message_average_max = ""
    message_average_min = ""
    message_std_max = ""
    message_std_mix = ""

    # 在学生成绩数据表格.csv文件中读取学生成绩数据
    student_score_date = pd.read_csv("学生成绩数据.csv", encoding="gbk")

    # 获取班级中各科成绩数据的汇总统计,并写入班级各科成绩数据汇总统计.csv文件
    describe_score_date = student_score_date[["高等数学", "英语", "Python", "Java", "C++"]].describe()
    describe_score_date.index = ["学生人数", "平均分", "标准差", "最低分", "1/4分位数", "中位数(二分之一分位数)", "3/4分位数", "最高分"]
    describe_score_date.to_csv("班级各科成绩数据汇总统计.csv", encoding='gbk', index=True, sep=',')

    # 获取班级中各科平均成绩
    class_average_score_math = describe_score_date.at["平均分", "高等数学"]
    class_average_score_english = describe_score_date.at["平均分", "英语"]
    class_average_score_python = describe_score_date.at["平均分", "Python"]
    class_average_score_java = describe_score_date.at["平均分", "Java"]
    class_average_score_cpp = describe_score_date.at["平均分", "C++"]

    # 获取班级中各科成绩的标准差
    class_std_score_math = describe_score_date.at["标准差", "高等数学"]
    class_std_score_english = describe_score_date.at["标准差", "英语"]
    class_std_score_python = describe_score_date.at["标准差", "Python"]
    class_std_score_java = describe_score_date.at["标准差", "Java"]
    class_std_score_cpp = describe_score_date.at["标准差", "C++"]

    # 获取班级中各科成绩的中位数
    class_median_score_math = describe_score_date.at["中位数(二分之一分位数)", "高等数学"]
    class_median_score_english = describe_score_date.at["中位数(二分之一分位数)", "英语"]
    class_median_score_python = describe_score_date.at["中位数(二分之一分位数)", "Python"]
    class_median_score_java = describe_score_date.at["中位数(二分之一分位数)", "Java"]
    class_median_score_cpp = describe_score_date.at["中位数(二分之一分位数)", "C++"]

    # 查看班级中各科成绩的最高分
    class_max_score_math = describe_score_date.at["最高分", "高等数学"]
    class_max_score_english = describe_score_date.at["最高分", "英语"]
    class_max_score_python = describe_score_date.at["最高分", "Python"]
    class_max_score_java = describe_score_date.at["最高分", "Java"]
    class_max_score_cpp = describe_score_date.at["最高分", "C++"]

    # 获取班级中各科成绩的最低分
    class_min_score_math = describe_score_date.at["最低分", "高等数学"]
    class_min_score_english = describe_score_date.at["最低分", "英语"]
    class_min_score_python = describe_score_date.at["最低分", "Python"]
    class_min_score_java = describe_score_date.at["最低分", "Java"]
    class_min_score_cpp = describe_score_date.at["最低分", "C++"]

    # 获取学生人数
    student_number = student_score_date.shape[0]  # 获取表格的行数

    # 对班级中各学生的成绩数据排序,并写入班级学生成绩排名.csv文件
    rank_student_score_date = student_score_date.sort_values(by="平均分", ascending=False)
    rank_student_score_date["排名"] = range(1, student_number+1)
    rank_student_score_date.to_csv("班级学生成绩排名.csv", encoding='gbk', index=False, sep=',')

    # 进行学生成绩数据分析,分析成绩的平均值
    class_average_score_list = [class_average_score_math, class_average_score_english, class_average_score_python, class_average_score_java, class_average_score_cpp]
    if max(class_average_score_list) == class_average_score_math:
        message_average_max = f"班级中成绩最好的科目是高等数学,其平均分为{class_average_score_math}。"
    elif max(class_average_score_list) == class_average_score_english:
        message_average_max = f"班级中成绩最好的科目是英语,其平均分为{class_average_score_english}。"
    elif max(class_average_score_list) == class_average_score_python:
        message_average_max = f"班级中成绩最好的科目是Python,其平均分为{class_average_score_python}。"
    elif max(class_average_score_list) == class_average_score_java:
        message_average_max = f"班级中成绩最好的科目是Java,其平均分为{class_average_score_java}。"
    elif max(class_average_score_list) == class_average_score_cpp:
        message_average_max = f"班级中成绩最好的科目是C++,其平均分为{class_average_score_cpp}。"

    if min(class_average_score_list) == class_average_score_math:
        message_average_min = f"班级中成绩最差的科目是高等数学,其平均分为{class_average_score_math}。"
    elif min(class_average_score_list) == class_average_score_english:
        message_average_min = f"班级中成绩最差的科目是英语,其平均分为{class_average_score_english}。"
    elif min(class_average_score_list) == class_average_score_python:
        message_average_min = f"班级中成绩最差的科目是Python,其平均分为{class_average_score_python}。"
    elif min(class_average_score_list) == class_average_score_java:
        message_average_min = f"班级中成绩最差的科目是Java,其平均分为{class_average_score_java}。"
    elif min(class_average_score_list) == class_average_score_cpp:
        message_average_min = f"班级中成绩最差的科目是C++,其平均分为{class_average_score_cpp}。"

    # 进行学生成绩数据分析,分析成绩的标准差
    class_std_score_list = [class_std_score_math, class_std_score_english, class_std_score_python, class_std_score_java, class_std_score_cpp]
    if max(class_std_score_list) == class_std_score_math:
        message_std_max = f"班级中成绩稳定性最差的科目是高等数学,其标准差为{class_std_score_math}。"
    elif max(class_std_score_list) == class_std_score_english:
        message_std_max = f"班级中成绩稳定性最差的科目是英语,其标准差为{class_std_score_english}。"
    elif max(class_std_score_list) == class_std_score_python:
        message_std_max = f"班级中成绩稳定性最差的科目是Python,其标准差为{class_std_score_python}。"
    elif max(class_std_score_list) == class_std_score_java:
        message_std_max = f"班级中成绩稳定性最差的科目是Java,其标准差为{class_std_score_java}。"
    elif max(class_std_score_list) == class_std_score_cpp:
        message_std_max = f"班级中成绩稳定性最差的科目是C++,其标准差为{class_std_score_cpp}。"

    if min(class_std_score_list) == class_std_score_math:
        message_std_mix = f"班级中成绩稳定性最好的科目是高等数学,其标准差为{class_std_score_math}。"
    elif min(class_std_score_list) == class_std_score_english:
        message_std_mix = f"班级中成绩稳定性最好的科目是英语,其标准差为{class_std_score_english}。"
    elif min(class_std_score_list) == class_std_score_python:
        message_std_mix = f"班级中成绩稳定性最好的科目是Python,其标准差为{class_std_score_python}。"
    elif min(class_std_score_list) == class_std_score_java:
        message_std_mix = f"班级中成绩稳定性最好的科目是Java,其标准差为{class_std_score_java}。"
    elif min(class_std_score_list) == class_std_score_cpp:
        message_std_mix = f"班级中成绩稳定性最好的科目是C++,其标准差为{class_std_score_cpp}。"

    message = f"本班有{student_number}名同学,对学生成绩数据分析有如下结论:\n1. {message_average_max}\n2. {message_average_min}\n3. {message_std_mix}\n4. {message_std_max}\n\n对学生成绩数据分析的详细结果已保存至程序所在路径。\n文件名:班级各科成绩数据汇总统计.csv\n文件名:班级学生成绩排名.csv"
    wx.MessageBox(message, caption="学生成绩数据分析的结果")  # 弹出提示框

def DrawingStatisticalGraphsFunctionForwx(self, event):
    """定义绘制统计图函数给wx"""

    message = ""

    # 在班级各科成绩数据汇总统计.csv文件中读取成绩统计数据
    describe_score_date = pd.read_csv("班级各科成绩数据汇总统计.csv", encoding="gbk", index_col=0)    # index_col=0:将第一列设为列索引

    # 获取班级中各科平均成绩
    class_average_score_math = describe_score_date.at["平均分", "高等数学"]
    class_average_score_english = describe_score_date.at["平均分", "英语"]
    class_average_score_python = describe_score_date.at["平均分", "Python"]
    class_average_score_java = describe_score_date.at["平均分", "Java"]
    class_average_score_cpp = describe_score_date.at["平均分", "C++"]

    # 计算班级中总的平均成绩
    class_average_score = (class_average_score_math+class_average_score_english+class_average_score_python+class_average_score_java+class_average_score_cpp) / 5

    # 获取班级中各科成绩的标准差
    class_std_score_math = describe_score_date.at["标准差", "高等数学"]
    class_std_score_english = describe_score_date.at["标准差", "英语"]
    class_std_score_python = describe_score_date.at["标准差", "Python"]
    class_std_score_java = describe_score_date.at["标准差", "Java"]
    class_std_score_cpp = describe_score_date.at["标准差", "C++"]

    # 计算班级中总的平均标准差
    class_std_score = (class_std_score_math+class_std_score_english+class_std_score_python+class_std_score_java+class_std_score_cpp) / 5

    def NormalDistribution(x, mu=50, sigma=5):
        """此函数返回正态分布的概率密度函数,x:输入待计算的值,μ:(mu)为期望,σ:(sigma为标准差"""

        # 0.3989422804014327 = 1.0 / math.sqrt(2 * math.pi),exp()函数返回x的指数:e^x。
        return 0.3989422804014327 / sigma * (math.exp(- (x - mu) * (x - mu) / (2 * sigma * sigma)))

    # 支持中文
    plt.rcParams["font.sans-serif"] = ["SimHei"]  # 用来正常显示中文标签
    plt.rcParams["axes.unicode_minus"] = False  # 用来正常显示负号

    # 设置mu和sigma
    mu = class_average_score
    sigma = class_std_score

    # 绘制正态分布曲线
    x_axis = []  # 横坐标
    for x in range(101):
        x_axis.append(x)

    y_axis = []  # 纵坐标
    for x in x_axis:
        y_axis.append(NormalDistribution(x, mu, sigma))

    plt.plot(x_axis, y_axis, color="black")

    # 填充正态分布曲线
    for i in range(1, 4):
        x_axis = np.linspace(mu - sigma * i, mu + sigma * i, 100)
        y_axis = scipy.stats.norm.pdf(x_axis, mu, sigma)

        plt.fill_between(x_axis, y_axis, 0, alpha=0.3, color="orange")

    # 绘制线条和文字
    percents = ["68.26%", "95.45%", "99.73%"]
    for i in range(1, 4):
        # 计算中间三个区间连线的两端坐标
        x1 = mu - sigma * i
        x2 = mu + sigma * i
        y1 = NormalDistribution(x1, mu, sigma)
        y2 = NormalDistribution(x2, mu, sigma)
        # 绘制三条线段,分别为左右1条和上下2条
        plt.plot([x1, x2], [y1, y2], color="black")
        plt.plot([x1, x1], [y1, 0], color="black")
        plt.plot([x2, x2], [y1, 0], color="black")
        # 绘制相应的文本
        plt.text(x1 - 12, y1, f"$\mu - {i}\sigma$", fontsize=14)
        plt.text(x2 + 3, y1, f"$\mu + {i}\sigma$", fontsize=14)
        plt.text((x1 + x2) / 2 - 2, y1, percents[i - 1], fontsize=14, color="black")

    # 绘制最上方的单个的mu
    plt.text(mu, NormalDistribution(mu, mu, sigma) + 0.0003, f"$\mu$", fontsize=14, color="black")

    # 设置图表标题和标题字号
    plt.title(f"班级综合成绩正态分布($\mu={'%0.1f' %mu}, \sigma={'%0.1f' %sigma}$)", fontsize=22)

    # 设置刻度的字号
    plt.tick_params(axis="both", which="major", labelsize=14)

    # 设置x,y轴标签及其字号
    plt.xlabel("分数", fontsize=14)
    plt.ylabel("分数概率", fontsize=14)

    # 设置X轴的边为0至100
    plt.xlim(0, 100)

    # 设置X轴的显示的内容为 [0, 10, 20, ..., 100]
    plt.xticks(range(0, 110, 10))

    # 设置背景网格
    plt.grid(color="black", alpha=0.2)

    # 保存绘制的图片
    plt.savefig("班级综合成绩正态分布曲线.png")

    # 显示绘制的图片
    plt.show()

    message = f"已绘制且已打开班级综合成绩正态分布曲线。\n\n班级综合成绩正态分布曲线的图片已保存至程序所在路径。\n文件名:班级综合成绩正态分布曲线.csv"
    wx.MessageBox(message, caption="班级综合成绩正态分布曲线的绘制结果")  # 弹出提示框

    # 用操作系统显示绘制的图片
    os.startfile("班级综合成绩正态分布曲线.png")  # 用操作系统打开图片
  1. 提高程序健壮性_代码文件.py:
"""

Python综合实验_成绩信息管理系统

综合实验要求:
    1.做图形用户界面(参考event.py源代码)。
      做登录界面,主界面,消息对话框(至少有这三部分)。
      做一个成绩统计功能,用三个文本框接收高数、英语、Python三科成绩。
      做一个按钮计算总分,一个按钮计算平均分。
      加异常处理,输入非数字字符弹出对话框提示“请输入数字”。
     (基本分20分)
    2.在1的基础上增加自定义异常类和异常处理,如输入0~100外的分数弹出对话框提示。
     (加10分)
    3.在前两个要求的基础上再增加其他的frame框架窗口和功能。
     (加10分)
    4.结合数据处理功能,做班级成绩数据并做出查询、绘图等功能。
     (加10分)

"""

"""
程序设计思路

1.用户数据和学生成绩数据的类
2.图形用户界面:wxPython模块
3.功能实现函数:调用用户数据和学生成绩数据的类中的方法
4.统计数据,绘制统计图的函数:pandas模块,matplotlib模块
5.提高程序健壮性:自定义异常类和异常处理

"""
# 5.提高程序健壮性:自定义异常类和异常处理
class NumericalRangeError(Exception):
    """当输入0~100以外的数字时引发该异常"""
    pass

四、交流学习

互联网开源精神需要大家一起互相交流学习,互相支持奉献。欢迎大家与我友好交流。

加我 QQ 好友获取所有项目源码和项目文档,感谢大家的支持!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

末影小黑xh

感谢朋友们对我的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值