我们使用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()