这个程序是一个学生成绩管理系统,它借助 Python 的 tkinter
库构建图形用户界面(GUI),利用 sqlite3
进行数据库管理,使用 matplotlib
生成图表,openpyxl
实现数据导出,主要具备以下功能:
1. 数据库管理
- 创建表格:在程序启动时,会自动连接到
students.db
数据库,并创建一个名为students
的表,该表包含学生的id
、name
(姓名)、math
(数学成绩)、english
(英语成绩)和science
(科学成绩)字段。 - 添加学生信息:用户可以通过界面上的 “添加学生” 选项,在弹出的对话框中输入学生的姓名和各科成绩,点击 “提交” 按钮后,数据会被插入到数据库中。
- 删除学生信息:用户在表格中选中某条学生记录,点击 “删除选中” 按钮,程序会从数据库中删除该学生的记录。
2. 数据展示与操作
- 数据展示:使用
ttk.Treeview
组件在界面上显示学生的信息,包括学生的 ID、姓名、各科成绩以及平均分。 - 数据刷新:点击 “刷新数据” 按钮,程序会清空当前表格中的数据,并从数据库中重新加载最新数据。
3. 数据导出
- 用户可以通过 “文件” 菜单中的 “导出到 Excel” 选项,选择保存路径,将学生的信息(包括 ID、姓名、各科成绩和平均分)导出到一个 Excel 文件中。
4. 图表生成
- 用户点击 “操作” 菜单中的 “生成图表” 选项,程序会弹出一个新窗口,显示一个柱状图,对比数学、英语、科学三科的平均分。
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import sqlite3
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import openpyxl
import matplotlib
# 设置中文字体
matplotlib.rcParams['font.family'] = 'SimHei' # 使用黑体字体,根据实际情况修改
# 解决负号显示问题
matplotlib.rcParams['axes.unicode_minus'] = False
# ================== 数据库操作类 ==================
class Database:
def __init__(self):
self.conn = sqlite3.connect('students.db')
self.cursor = self.conn.cursor()
self.create_table()
def create_table(self):
self.cursor.execute('''CREATE TABLE IF NOT EXISTS students (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
math INTEGER,
english INTEGER,
science INTEGER)''')
self.conn.commit()
def add_student(self, name, math, english, science):
self.cursor.execute('''INSERT INTO students (name, math, english, science)
VALUES (?, ?, ?, ?)''', (name, math, english, science))
self.conn.commit()
def get_students(self):
self.cursor.execute("SELECT * FROM students")
return self.cursor.fetchall()
def delete_student(self, student_id):
self.cursor.execute("DELETE FROM students WHERE id=?", (student_id,))
self.conn.commit()
# ================== 主应用程序 ==================
class StudentManagerApp:
def __init__(self, root):
self.root = root
self.db = Database()
self.root.title("学生成绩管理系统")
self.root.geometry("600x300")
# 创建菜单栏
self.create_menu()
# 创建主界面
self.create_main_interface()
# 加载数据
self.refresh_data()
def create_menu(self):
menubar = tk.Menu(self.root)
# 文件菜单
file_menu = tk.Menu(menubar, tearoff=0)
file_menu.add_command(label="导出到Excel", command=self.export_to_excel)
file_menu.add_separator()
file_menu.add_command(label="退出", command=self.root.quit)
menubar.add_cascade(label="文件", menu=file_menu)
# 数据菜单
data_menu = tk.Menu(menubar, tearoff=0)
data_menu.add_command(label="添加学生", command=self.show_add_dialog)
data_menu.add_command(label="生成图表", command=self.show_chart)
menubar.add_cascade(label="操作", menu=data_menu)
self.root.config(menu=menubar)
def create_main_interface(self):
# 创建Treeview表格
columns = ("ID", "姓名", "数学", "英语", "科学", "平均分")
self.tree = ttk.Treeview(self.root, columns=columns, show='headings', selectmode='browse')
# 设置列宽和标题
col_widths = [50, 120, 80, 80, 80, 150]
for col, width in zip(columns, col_widths):
self.tree.heading(col, text=col)
self.tree.column(col, width=width, anchor='center')
# 添加滚动条
scrollbar = ttk.Scrollbar(self.root, orient=tk.VERTICAL, command=self.tree.yview)
self.tree.configure(yscroll=scrollbar.set)
# 布局
self.tree.grid(row=0, column=0, sticky='nsew')
scrollbar.grid(row=0, column=1, sticky='ns')
# 底部按钮
btn_frame = tk.Frame(self.root)
btn_frame.grid(row=1, column=0, columnspan=2, pady=10)
ttk.Button(btn_frame, text="删除选中", command=self.delete_selected).pack(side=tk.LEFT, padx=5)
ttk.Button(btn_frame, text="刷新数据", command=self.refresh_data).pack(side=tk.LEFT, padx=5)
def refresh_data(self):
# 清空现有数据
for item in self.tree.get_children():
self.tree.delete(item)
# 从数据库加载数据
for student in self.db.get_students():
average = sum(student[2:5]) / 3
self.tree.insert('', 'end', values=(student[0], student[1], student[2], student[3], student[4], average))
def show_add_dialog(self):
# 创建添加学生对话框
dialog = tk.Toplevel(self.root)
dialog.title("添加学生")
dialog.geometry("300x200")
# 表单项
ttk.Label(dialog, text="姓名:").grid(row=0, column=0, padx=5, pady=5)
name_entry = ttk.Entry(dialog)
name_entry.grid(row=0, column=1, padx=5, pady=5)
ttk.Label(dialog, text="数学:").grid(row=1, column=0, padx=5, pady=5)
math_entry = ttk.Entry(dialog)
math_entry.grid(row=1, column=1, padx=5, pady=5)
ttk.Label(dialog, text="英语:").grid(row=2, column=0, padx=5, pady=5)
english_entry = ttk.Entry(dialog)
english_entry.grid(row=2, column=1, padx=5, pady=5)
ttk.Label(dialog, text="科学:").grid(row=3, column=0, padx=5, pady=5)
science_entry = ttk.Entry(dialog)
science_entry.grid(row=3, column=1, padx=5, pady=5)
# 提交按钮
def submit():
try:
self.db.add_student(
name_entry.get(),
int(math_entry.get()),
int(english_entry.get()),
int(science_entry.get())
)
self.refresh_data()
dialog.destroy()
except ValueError:
messagebox.showerror("错误", "请输入有效的数字成绩")
ttk.Button(dialog, text="提交", command=submit).grid(row=4, columnspan=2, pady=10)
def delete_selected(self):
selected = self.tree.selection()
if not selected:
messagebox.showwarning("警告", "请先选择要删除的学生")
return
student_id = self.tree.item(selected[0])['values'][0]
self.db.delete_student(student_id)
self.refresh_data()
def show_chart(self):
# 创建图表窗口
chart_window = tk.Toplevel(self.root)
chart_window.title("成绩分布图")
# 获取数据
students = self.db.get_students()
if not students:
messagebox.showwarning("警告", "没有数据可供生成图表")
return
math_scores = [s[2] for s in students]
english_scores = [s[3] for s in students]
science_scores = [s[4] for s in students]
# 计算平均分
math_avg = sum(math_scores) / len(math_scores)
english_avg = sum(english_scores) / len(english_scores)
science_avg = sum(science_scores) / len(science_scores)
# 创建图表
fig = plt.Figure(figsize=(6, 4))
ax = fig.add_subplot(111)
ax.bar(['数学', '英语', '科学'], [math_avg, english_avg, science_avg], color=['blue', 'orange', 'green'])
ax.set_title('科目平均分对比')
ax.set_ylabel('平均分')
# 嵌入到Tkinter
canvas = FigureCanvasTkAgg(fig, master=chart_window)
canvas.draw()
canvas.get_tk_widget().pack()
def export_to_excel(self):
file_path = filedialog.asksaveasfilename(
defaultextension=".xlsx",
filetypes=[("Excel文件", "*.xlsx")]
)
if file_path:
try:
# 创建一个新的 Excel 工作簿
workbook = openpyxl.Workbook()
sheet = workbook.active
sheet.title = "学生成绩"
# 添加表头
columns = ("ID", "姓名", "数学", "英语", "科学", "平均分")
sheet.append(columns)
# 获取数据库中的学生数据
students = self.db.get_students()
for student in students:
average = sum(student[2:5]) / 3
row = (student[0], student[1], student[2], student[3], student[4], average)
sheet.append(row)
# 保存工作簿
workbook.save(file_path)
messagebox.showinfo("成功", f"数据已保存到 {file_path}")
except Exception as e:
messagebox.showerror("错误", f"导出数据时出现错误: {e}")
if __name__ == "__main__":
root = tk.Tk()
app = StudentManagerApp(root)
root.mainloop()