From 100c9db2ee410c4f22ee1160cbcd492c06bdaf9a Mon Sep 17 00:00:00 2001 From: fzu102301523 <102301523@fzu.edu.cn> Date: Sat, 22 Nov 2025 09:19:42 +0800 Subject: [PATCH] ADD file via upload --- main_ui.py | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 main_ui.py diff --git a/main_ui.py b/main_ui.py new file mode 100644 index 0000000..d1a6aa2 --- /dev/null +++ b/main_ui.py @@ -0,0 +1,178 @@ +import tkinter as tk +from tkinter import ttk, filedialog, messagebox +import matplotlib.pyplot as plt +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg +from db_operate import DBHelper +from excel_operate import import_students_from_excel, export_score_to_excel +from call_logic import CallLogic + +# 设置matplotlib中文显示 +plt.rcParams["font.family"] = "SimHei" +plt.rcParams["axes.unicode_minus"] = False + +class CallSystemUI: + def __init__(self, root): + self.root = root + self.root.title("课堂随机点名系统") + self.root.geometry("800x600") + self.call_logic = CallLogic() + self.create_widgets() + + def create_widgets(self): + """创建界面组件""" + # 顶部按钮栏 + btn_frame = ttk.Frame(self.root) + btn_frame.pack(pady=10, fill=tk.X) + + # 导入Excel按钮 + ttk.Button(btn_frame, text="导入学生名单", command=self.import_excel).pack(side=tk.LEFT, padx=5) + # 随机点名按钮 + ttk.Button(btn_frame, text="随机点名", command=self.random_call).pack(side=tk.LEFT, padx=5) + # 顺序点名按钮 + ttk.Button(btn_frame, text="顺序点名", command=self.order_call).pack(side=tk.LEFT, padx=5) + # 可视化按钮 + ttk.Button(btn_frame, text="积分可视化", command=self.show_visual).pack(side=tk.LEFT, padx=5) + # 导出积分按钮 + ttk.Button(btn_frame, text="导出积分详单", command=self.export_excel).pack(side=tk.LEFT, padx=5) + + # 点名结果展示区 + self.result_frame = ttk.LabelFrame(self.root, text="点名结果") + self.result_frame.pack(pady=10, fill=tk.X, padx=20) + self.result_label = ttk.Label(self.result_frame, text="等待点名...", font=("Arial", 16)) + self.result_label.pack(pady=20) + + # 积分记录按钮区(点名后显示) + self.record_frame = ttk.Frame(self.root) + self.record_frame.pack(pady=10, fill=tk.X, padx=20) + self.student_id_var = tk.StringVar() # 存储选中学生的学号 + + # 学生名单表格 + self.table_frame = ttk.Frame(self.root) + self.table_frame.pack(pady=10, fill=tk.BOTH, expand=True, padx=20) + self.tree = ttk.Treeview(self.table_frame, columns=("学号", "姓名", "专业", "总积分", "点名次数"), show="headings") + self.tree.heading("学号", text="学号") + self.tree.heading("姓名", text="姓名") + self.tree.heading("专业", text="专业") + self.tree.heading("总积分", text="总积分") + self.tree.heading("点名次数", text="随机点名次数") + self.tree.pack(fill=tk.BOTH, expand=True) + self.refresh_table() + + def import_excel(self): + """导入Excel学生名单""" + file_path = filedialog.askopenfilename(filetypes=[("Excel文件", "*.xlsx")]) + if not file_path: + return + success, msg = import_students_from_excel(file_path) + messagebox.showinfo("导入结果", msg) + self.refresh_table() + + def export_excel(self): + """导出积分详单""" + file_path = filedialog.asksaveasfilename(defaultextension=".xlsx", filetypes=[("Excel文件", "*.xlsx")]) + if not file_path: + return + success, msg = export_score_to_excel(file_path) + messagebox.showinfo("导出结果", msg) + + def random_call(self): + """随机点名""" + student, msg = self.call_logic.random_call() + if not student: + messagebox.showwarning("警告", msg) + return + # 展示结果 + self.result_label.config(text=f"随机点名结果:\n学号:{student[0]} 姓名:{student[1]} 专业:{student[2]} 总积分:{student[3]}") + self.student_id_var.set(student[0]) + # 显示积分记录按钮 + self.show_record_buttons("random") + + def order_call(self): + """顺序点名""" + student, msg = self.call_logic.order_call() + if not student: + messagebox.showwarning("警告", msg) + return + self.result_label.config(text=f"顺序点名结果:\n学号:{student[0]} 姓名:{student[1]} 专业:{student[2]} 总积分:{student[3]}") + self.student_id_var.set(student[0]) + # 显示积分记录按钮 + self.show_record_buttons("order") + + def show_record_buttons(self, call_mode): + """显示积分记录按钮(到课/回答问题)""" + # 清空原有按钮 + for widget in self.record_frame.winfo_children(): + widget.destroy() + # 创建按钮 + ttk.Button(self.record_frame, text="到课(+1分)", command=lambda: self.record_score(call_mode, True, 0)).pack(side=tk.LEFT, padx=5) + ttk.Button(self.record_frame, text="未到课(0分)", command=lambda: self.record_score(call_mode, False, 0)).pack(side=tk.LEFT, padx=5) + ttk.Button(self.record_frame, text="准确重复问题(+0.5分)", command=lambda: self.record_score(call_mode, True, 0.5)).pack(side=tk.LEFT, padx=5) + ttk.Button(self.record_frame, text="重复问题错误(-1分)", command=lambda: self.record_score(call_mode, True, -1)).pack(side=tk.LEFT, padx=5) + ttk.Button(self.record_frame, text="回答正确(+2分)", command=lambda: self.record_score(call_mode, True, 2)).pack(side=tk.LEFT, padx=5) + + def record_score(self, call_mode, is_arrived, answer_score): + """记录积分""" + student_id = self.student_id_var.get() + if not student_id: + messagebox.showwarning("警告", "无学生信息") + return + success = self.call_logic.record_call_result(student_id, call_mode, is_arrived, answer_score) + if success: + messagebox.showinfo("成功", "积分记录成功") + self.refresh_table() + else: + messagebox.showerror("错误", "积分记录失败") + + def refresh_table(self): + """刷新学生名单表格""" + # 清空表格 + for item in self.tree.get_children(): + self.tree.delete(item) + # 重新加载数据 + db = DBHelper() + students = db.get_all_students() + db.close() + for student in students: + self.tree.insert("", tk.END, values=(student[0], student[1], student[2], student[3], student[4])) + + def show_visual(self): + """积分可视化""" + # 创建新窗口 + visual_window = tk.Toplevel(self.root) + visual_window.title("积分可视化") + visual_window.geometry("800x500") + # 获取数据 + db = DBHelper() + students = db.get_all_students() + db.close() + if not students: + messagebox.showwarning("警告", "无学生数据") + return + # 取TOP10学生 + students_sorted = sorted(students, key=lambda x: x[3], reverse=True)[:10] + names = [s[1] for s in students_sorted] + scores = [s[3] for s in students_sorted] + call_nums = [s[4] for s in students_sorted] + # 创建图表 + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4)) + # 柱形图:积分排名 + ax1.bar(names, scores, color="skyblue") + ax1.set_title("TOP10学生积分排名") + ax1.set_xlabel("姓名") + ax1.set_ylabel("总积分") + ax1.tick_params(axis='x', rotation=45) + # 折线图:随机点名次数 + ax2.plot(names, call_nums, marker="o", color="orange") + ax2.set_title("TOP10学生随机点名次数") + ax2.set_xlabel("姓名") + ax2.set_ylabel("点名次数") + ax2.tick_params(axis='x', rotation=45) + # 嵌入Tkinter窗口 + canvas = FigureCanvasTkAgg(fig, master=visual_window) + canvas.draw() + canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True) + +if __name__ == "__main__": + root = tk.Tk() + app = CallSystemUI(root) + root.mainloop()