import tkinter as tk
from tkinter import ttk, messagebox
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np

class GradeTrendApp:
    def __init__(self, root):
        self.root = root
        self.root.title("成绩走势图分析系统")
        self.root.geometry("1000x700")
        
        # 存储成绩数据
        self.subjects = ["语文", "数学", "英语", "物理", "化学"]
        self.exam_names = []
        self.grades_data = {}  # {科目: [成绩列表]}
        
        # 初始化各科目成绩列表
        for subject in self.subjects:
            self.grades_data[subject] = []
        
        # 创建UI
        self.create_widgets()
    
    def create_widgets(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 输入区域
        input_frame = ttk.LabelFrame(main_frame, text="添加考试成绩", padding="10")
        input_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 20))
        
        # 考试名称
        ttk.Label(input_frame, text="考试名称:").grid(row=0, column=0, padx=5)
        self.exam_name_entry = ttk.Entry(input_frame, width=15)
        self.exam_name_entry.grid(row=0, column=1, padx=5)
        
        # 各科成绩输入
        self.grade_entries = {}
        for i, subject in enumerate(self.subjects):
            row = i // 3
            col = (i % 3) * 2 + 2
            
            ttk.Label(input_frame, text=f"{subject}:").grid(row=row, column=col, padx=(10 if col > 2 else 5, 5))
            
            entry = ttk.Entry(input_frame, width=8)
            entry.grid(row=row, column=col+1, padx=5)
            self.grade_entries[subject] = entry
        
        # 按钮区域
        button_frame = ttk.Frame(input_frame)
        button_frame.grid(row=2, column=0, columnspan=8, pady=(10, 0))
        
        ttk.Button(button_frame, text="添加成绩", command=self.add_grades).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="清空数据", command=self.clear_data).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="查看统计", command=self.show_statistics).pack(side=tk.LEFT, padx=5)
        
        # 图表显示区域
        chart_frame = ttk.LabelFrame(main_frame, text="成绩走势图", padding="10")
        chart_frame.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 创建matplotlib图表
        self.fig, self.ax = plt.subplots(figsize=(10, 6))
        self.fig.patch.set_facecolor('#f0f0f0')
        
        self.canvas = FigureCanvasTkAgg(self.fig, master=chart_frame)
        self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        # 控制选项
        control_frame = ttk.Frame(main_frame)
        control_frame.grid(row=2, column=0, columnspan=2, pady=(10, 0))
        
        ttk.Label(control_frame, text="选择显示科目:").pack(side=tk.LEFT, padx=5)
        
        self.selected_subjects = {}
        for subject in self.subjects:
            var = tk.BooleanVar(value=True)
            self.selected_subjects[subject] = var
            ttk.Checkbutton(control_frame, text=subject, variable=var, 
                          command=self.update_chart).pack(side=tk.LEFT, padx=2)
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(0, weight=1)
        main_frame.rowconfigure(1, weight=1)
    
    def add_grades(self):
        """添加成绩"""
        exam_name = self.exam_name_entry.get().strip()
        if not exam_name:
            messagebox.showwarning("警告", "请输入考试名称！")
            return
        
        # 检查考试名称是否重复
        if exam_name in self.exam_names:
            messagebox.showwarning("警告", f"考试'{exam_name}'已存在！")
            return
        
        grades = []
        for subject in self.subjects:
            grade_str = self.grade_entries[subject].get().strip()
            if not grade_str:
                messagebox.showwarning("警告", f"请输入{subject}成绩！")
                return
            
            try:
                grade = float(grade_str)
                if grade < 0 or grade > 150:
                    messagebox.showwarning("警告", f"{subject}成绩应在0-150之间！")
                    return
                grades.append(grade)
            except ValueError:
                messagebox.showwarning("警告", f"{subject}成绩格式不正确！")
                return
        
        # 保存数据
        self.exam_names.append(exam_name)
        for i, subject in enumerate(self.subjects):
            self.grades_data[subject].append(grades[i])
        
        # 清空输入
        self.exam_name_entry.delete(0, tk.END)
        for entry in self.grade_entries.values():
            entry.delete(0, tk.END)
        
        # 更新图表
        self.update_chart()
        messagebox.showinfo("成功", f"已添加'{exam_name}'的成绩数据！")
    
    def clear_data(self):
        """清空所有数据"""
        if messagebox.askyesno("确认", "确定要清空所有数据吗？"):
            self.exam_names.clear()
            for subject in self.subjects:
                self.grades_data[subject].clear()
            self.update_chart()
            messagebox.showinfo("成功", "数据已清空！")
    
    def update_chart(self):
        """更新图表"""
        self.ax.clear()
        
        if not self.exam_names:
            self.ax.text(0.5, 0.5, '暂无数据\n请添加考试成绩', 
                        ha='center', va='center', fontsize=14)
            self.canvas.draw()
            return
        
        x = range(len(self.exam_names))
        colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']
        
        # 绘制选中的科目
        for i, subject in enumerate(self.subjects):
            if self.selected_subjects[subject].get() and self.grades_data[subject]:
                self.ax.plot(x, self.grades_data[subject], marker='o', 
                           label=subject, color=colors[i], linewidth=2, markersize=6)
                
                # 标注数值
                for j, grade in enumerate(self.grades_data[subject]):
                    self.ax.annotate(str(int(grade)), (j, grade), 
                                   textcoords="offset points", xytext=(0,10),
                                   ha='center', fontsize=9, color=colors[i])
        
        # 设置图表样式
        self.ax.set_xlabel('考试名称', fontsize=12)
        self.ax.set_ylabel('成绩', fontsize=12)
        self.ax.set_title('成绩走势图', fontsize=14, fontweight='bold')
        self.ax.set_xticks(x)
        self.ax.set_xticklabels(self.exam_names, rotation=45, ha='right')
        self.ax.legend(loc='upper left', bbox_to_anchor=(1, 1))
        self.ax.grid(True, alpha=0.3)
        self.ax.set_ylim(0, 160)
        
        # 自动调整布局
        self.fig.tight_layout()
        self.canvas.draw()
    
    def show_statistics(self):
        """显示统计数据"""
        if not self.exam_names:
            messagebox.showinfo("提示", "暂无数据可统计！")
            return
        
        stats_window = tk.Toplevel(self.root)
        stats_window.title("成绩统计分析")
        stats_window.geometry("500x400")
        
        # 创建表格
        tree = ttk.Treeview(stats_window, columns=("科目", "平均分", "最高分", "最低分", "最近成绩"), 
                           show="headings", height=10)
        
        tree.heading("科目", text="科目")
        tree.heading("平均分", text="平均分")
        tree.heading("最高分", text="最高分")
        tree.heading("最低分", text="最低分")
        tree.heading("最近成绩", text="最近成绩")
        
        tree.column("科目", width=80)
        tree.column("平均分", width=80)
        tree.column("最高分", width=80)
        tree.column("最低分", width=80)
        tree.column("最近成绩", width=80)
        
        for subject in self.subjects:
            if self.grades_data[subject]:
                avg = np.mean(self.grades_data[subject])
                max_grade = max(self.grades_data[subject])
                min_grade = min(self.grades_data[subject])
                recent = self.grades_data[subject][-1]
                
                tree.insert("", tk.END, values=(
                    subject,
                    f"{avg:.1f}",
                    f"{max_grade:.0f}",
                    f"{min_grade:.0f}",
                    f"{recent:.0f}"
                ))
        
        tree.pack(padx=20, pady=20, fill=tk.BOTH, expand=True)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(stats_window, orient=tk.VERTICAL, command=tree.yview)
        tree.configure(yscrollcommand=scrollbar.set)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

def main():
    root = tk.Tk()
    app = GradeTrendApp(root)
    root.mainloop()

if __name__ == "__main__":
    main()