Tkinter GUI 程序实现一个简易的学生成绩管理系统

这个程序是一个学生成绩管理系统,它借助 Python 的 tkinter 库构建图形用户界面(GUI),利用 sqlite3 进行数据库管理,使用 matplotlib 生成图表,openpyxl 实现数据导出,主要具备以下功能:

1. 数据库管理

  • 创建表格:在程序启动时,会自动连接到 students.db 数据库,并创建一个名为 students 的表,该表包含学生的 idname(姓名)、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()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值