python入门代码案例:学生成绩管理系统

我们使用python代码实现的学生成绩管理系统。从图中可以增添学生信息,进行提交,用户可以非常直观地看到最低分与最高分以及平均分数。

同时增加了可视化的统计图表,学生的分级分布水平可以很好的展现出来。

import json
import tkinter as tk
from tkinter import ttk, messagebox
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
from dataclasses import dataclass
from typing import List

# 设置全局中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 解决matplotlib中文问题
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题


# 学生数据类
@dataclass
class Student:
    id: str
    name: str
    gender: str  # 'M'/'F'
    score: float


class GradeManager:
    def __init__(self, data_file='students.json'):
        self.students: List[Student] = []
        self.data_file = data_file
        self.load_data()

    def add_student(self, stu_id, name, gender, score):
        """添加学生并验证数据"""
        # 检查学号唯一性
        if any(s.id == stu_id for s in self.students):
            raise ValueError("学号已存在")

        # 处理性别输入
        gender = gender.upper().strip()
        if gender not in {'M', 'F'}:
            raise ValueError("性别必须输入 M 或 F")

        # 验证成绩格式
        try:
            score = float(score)
        except ValueError:
            raise ValueError("成绩必须为数字")

        if not (0 <= score <= 100):
            raise ValueError("成绩需在 0-100 之间")

        # 添加学生记录
        self.students.append(Student(stu_id, name, gender, score))
        self.save_data()

    def get_statistics(self):
        """获取统计结果"""
        scores = [s.score for s in self.students]
        if not scores:
            return "⚠️ 无可用数据"

        max_score = max(scores)
        min_score = min(scores)
        avg_score = sum(scores) / len(scores)

        eval_count = self._get_evaluation_counts()

        stats = ("📊 统计结果:\n"
                 f"最高分: {max_score} | 最低分: {min_score} | 平均分: {avg_score:.2f}\n\n"
                 "📝 评价分布:\n")
        stats += "\n".join([f"{grade}: {count}人" for grade, count in eval_count.items()])
        return stats

    def _get_evaluation_counts(self):
        """计算成绩评价分布"""
        evaluations = {
            '优秀': lambda x: x >= 90,
            '良好': lambda x: 80 <= x < 90,
            '中等': lambda x: 70 <= x < 80,
            '及格': lambda x: 60 <= x < 70,
            '不及格': lambda x: x < 60
        }
        eval_count = {key: 0 for key in evaluations}
        for s in self.students:
            for grade, condition in evaluations.items():
                if condition(s.score):
                    eval_count[grade] += 1
                    break
        return eval_count

    def get_gender_analysis(self):
        """性别维度分析"""
        male = [s.score for s in self.students if s.gender == 'M']
        female = [s.score for s in self.students if s.gender == 'F']

        result = "👥 性别分析:\n"
        result += f"男生平均分: {sum(male) / len(male):.1f}\n" if male else "无男生数据\n"
        result += f"女生平均分: {sum(female) / len(female):.1f}\n" if female else "无女生数据"
        return result

    def plot_distribution(self):
        """生成成绩分布图(修复中文显示)"""
        font = FontProperties(fname=r"c:\windows\fonts\simhei.ttf", size=12)

        plt.style.use('ggplot')
        scores = [s.score for s in self.students]

        plt.figure(figsize=(10, 5))
        plt.hist(scores, bins=10, color='#4CAF50', edgecolor='black')
        plt.title('成绩分布直方图', fontproperties=font)
        plt.xlabel('分数段', fontproperties=font)
        plt.ylabel('人数', fontproperties=font)
        plt.xticks(fontproperties=font)
        plt.yticks(fontproperties=font)
        plt.grid(True)
        plt.show()

    def save_data(self):
        """保存数据到文件"""
        try:
            with open(self.data_file, 'w', encoding='utf-8') as f:
                json.dump([s.__dict__ for s in self.students],
                          f, indent=2, ensure_ascii=False)
        except Exception as e:
            raise RuntimeError(f"数据保存失败: {str(e)}")

    def load_data(self):
        """从文件加载数据"""
        try:
            with open(self.data_file, 'r', encoding='utf-8') as f:
                data = json.load(f)
                self.students = [Student(**item) for item in data]
        except FileNotFoundError:
            self.students = []
        except Exception as e:
            raise RuntimeError(f"数据加载失败: {str(e)}")


class GradeManagerGUI:
    def __init__(self, master):
        self.master = master
        self.setup_font()
        self.manager = GradeManager()
        self.setup_ui()

    def setup_font(self):
        """配置全局字体"""
        # 设置Tkinter默认字体
        default_font = ('Microsoft YaHei', 10)
        self.master.option_add("*Font", default_font)

        # 设置对话框字体
        dialog_font = ('Microsoft YaHei', 9)
        self.master.option_add("*Toplevel*Font", dialog_font)

        # 设置按钮特殊字体
        button_font = ('Microsoft YaHei', 10, 'bold')
        self.master.option_add("*Button*Font", button_font)

    def setup_ui(self):
        """初始化用户界面"""
        self.master.title("学生成绩管理系统 v2.1")
        self.master.geometry("900x650")

        # 主界面布局
        main_frame = ttk.Frame(self.master)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=15, pady=15)

        # 左侧功能面板
        control_panel = ttk.Frame(main_frame, width=120)
        control_panel.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 10))

        # 功能按钮
        buttons = [
            ("添加学生", self.show_add_dialog),
            ("查看统计", self.show_statistics),
            ("性别分析", self.show_gender_analysis),
            ("生成图表", self.manager.plot_distribution),
            ("退出系统", self.master.quit)
        ]

        for text, cmd in buttons:
            btn = ttk.Button(control_panel, text=text, command=cmd)
            btn.pack(pady=8, fill=tk.X)

        # 右侧结果显示区
        self.result_area = tk.Text(
            main_frame,
            wrap=tk.WORD,
            font=('Microsoft YaHei', 11),
            padx=10,
            pady=10
        )
        self.result_area.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)

        # 滚动条
        scrollbar = ttk.Scrollbar(main_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.result_area.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.result_area.yview)

    def show_add_dialog(self):
        """显示添加学生对话框"""
        dialog = tk.Toplevel(self.master)
        dialog.title("添加学生信息")
        dialog.resizable(False, False)

        fields = [
            ('学号', 'id'),
            ('姓名', 'name'),
            ('性别 (M/F)', 'gender'),
            ('成绩 (0-100)', 'score')
        ]

        entries = {}
        for row, (label, field) in enumerate(fields):
            ttk.Label(dialog, text=label).grid(row=row, column=0, padx=8, pady=6, sticky='e')
            entry = ttk.Entry(dialog, font=('Microsoft YaHei', 10))
            if field == 'score':
                entry.config(validate="key",
                             validatecommand=(dialog.register(self.validate_number), '%P'))
            entry.grid(row=row, column=1, padx=8, pady=6, ipadx=20)
            entries[field] = entry

        def submit():
            try:
                data = {
                    'stu_id': entries['id'].get().strip(),
                    'name': entries['name'].get().strip(),
                    'gender': entries['gender'].get().strip(),
                    'score': entries['score'].get().strip()
                }
                self.manager.add_student(**data)
                messagebox.showinfo("操作成功", "学生信息已添加!", parent=dialog)
                dialog.destroy()
            except Exception as e:
                messagebox.showerror("输入错误", str(e), parent=dialog)

        ttk.Button(dialog, text="提 交", command=submit).grid(
            row=len(fields), columnspan=2, pady=12, padx=8, sticky='ew')

    def validate_number(self, value):
        """验证数字输入"""
        if value == "":
            return True
        try:
            float(value)
            return True
        except ValueError:
            return value.count('.') == 1 and value.replace('.', '').isdigit()

    def show_statistics(self):
        """显示统计结果"""
        self.result_area.delete(1.0, tk.END)
        try:
            stats = self.manager.get_statistics()
            self.result_area.insert(tk.END, stats)
        except Exception as e:
            messagebox.showerror("错误", str(e))

    def show_gender_analysis(self):
        """显示性别分析"""
        self.result_area.delete(1.0, tk.END)
        try:
            analysis = self.manager.get_gender_analysis()
            self.result_area.insert(tk.END, analysis)
        except Exception as e:
            messagebox.showerror("错误", str(e))


if __name__ == "__main__":
    root = tk.Tk()
    try:
        app = GradeManagerGUI(root)
        root.mainloop()
    except Exception as e:
        messagebox.showerror("系统错误", f"程序初始化失败: {str(e)}")
        root.destroy()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值