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

class GradeTrendApp:
    def __init__(self, master):
        self.master = master
        master.title("成绩走势图生成器")
        master.geometry("900x750") # 设置初始窗口大小
        master.minsize(700, 600)   # 设置最小窗口大小

        # 成绩数据存储：
        # self.grades_data 结构示例:
        # {
        #     "数学": {"期中": 80, "期末": 85, "模拟一": 90},
        #     "语文": {"期中": 75, "期末": 80, "模拟一": 78}
        # }
        self.grades_data = {}
        # self.exams 存储所有出现过的考试名称，并保持有序，用于图表的X轴
        self.exams = [] 

        self._create_widgets()
        self._setup_plot()
        self.generate_chart() # 初始显示一个空图表

    def _create_widgets(self):
        # --- 控制面板框架 ---
        control_frame = tk.Frame(self.master, bd=2, relief=tk.GROOVE, padx=10, pady=10)
        control_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)

        tk.Label(control_frame, text="添加成绩数据点", font=("Microsoft YaHei", 14, "bold")).grid(row=0, column=0, columnspan=6, pady=(0, 10))

        # 科目输入
        tk.Label(control_frame, text="科目名称:", font=("Microsoft YaHei", 10)).grid(row=1, column=0, sticky=tk.W, pady=2)
        self.subject_entry = tk.Entry(control_frame, width=15, font=("Microsoft YaHei", 10))
        self.subject_entry.grid(row=1, column=1, padx=5, pady=2)

        # 考试输入
        tk.Label(control_frame, text="考试名称:", font=("Microsoft YaHei", 10)).grid(row=1, column=2, sticky=tk.W, pady=2)
        self.exam_entry = tk.Entry(control_frame, width=15, font=("Microsoft YaHei", 10))
        self.exam_entry.grid(row=1, column=3, padx=5, pady=2)

        # 成绩输入
        tk.Label(control_frame, text="成绩 (0-100):", font=("Microsoft YaHei", 10)).grid(row=1, column=4, sticky=tk.W, pady=2)
        self.grade_entry = tk.Entry(control_frame, width=10, font=("Microsoft YaHei", 10))
        self.grade_entry.grid(row=1, column=5, padx=5, pady=2)

        # 按钮区域
        button_frame = tk.Frame(control_frame)
        button_frame.grid(row=2, column=0, columnspan=6, pady=10)

        add_button = tk.Button(button_frame, text="添加成绩点", command=self.add_grade_point, font=("Microsoft YaHei", 10), bg="#4CAF50", fg="white")
        add_button.pack(side=tk.LEFT, padx=10)

        generate_button = tk.Button(button_frame, text="生成走势图", command=self.generate_chart, font=("Microsoft YaHei", 10, "bold"), bg="#2196F3", fg="white")
        generate_button.pack(side=tk.LEFT, padx=10)

        clear_button = tk.Button(button_frame, text="清除所有数据", command=self.clear_all_data, font=("Microsoft YaHei", 10), bg="#f44336", fg="white")
        clear_button.pack(side=tk.LEFT, padx=10)

        # --- 图表显示框架 ---
        self.plot_frame = tk.Frame(self.master, bd=2, relief=tk.SUNKEN)
        self.plot_frame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True, padx=10, pady=5)

    def _setup_plot(self):
        # 创建一个matplotlib图形和坐标轴
        # figsize=(宽度, 高度) 单位是英寸
        self.fig, self.ax = plt.subplots(figsize=(8, 6), dpi=100) 
        self.ax.set_title("成绩走势图", fontproperties='Microsoft YaHei', fontsize=16)
        self.ax.set_xlabel("考试", fontproperties='Microsoft YaHei', fontsize=12)
        self.ax.set_ylabel("成绩", fontproperties='Microsoft YaHei', fontsize=12)
        self.ax.set_ylim(0, 100) # 成绩范围通常是0-100
        self.ax.grid(True)
        
        # 设置中文字体
        plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei'] # 指定默认字体
        plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题

        # 将matplotlib图形嵌入到Tkinter
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.plot_frame)
        self.canvas_widget = self.canvas.get_tk_widget()
        self.canvas_widget.pack(side=tk.TOP, fill=tk.BOTH, expand=True)

        # 添加matplotlib工具栏（缩放、平移、保存等）
        self.toolbar = NavigationToolbar2Tk(self.canvas, self.plot_frame)
        self.toolbar.update()
        self.canvas_widget.pack(side=tk.TOP, fill=tk.BOTH, expand=True)

    def add_grade_point(self):
        """添加一个成绩点到数据中"""
        subject = self.subject_entry.get().strip()
        exam = self.exam_entry.get().strip()
        grade_str = self.grade_entry.get().strip()

        if not subject or not exam or not grade_str:
            messagebox.showwarning("输入错误", "科目、考试和成绩都不能为空。", parent=self.master)
            return

        try:
            grade = float(grade_str)
            if not (0 <= grade <= 100):
                messagebox.showwarning("输入错误", "成绩必须在0到100之间。", parent=self.master)
                return
        except ValueError:
            messagebox.showwarning("输入错误", "成绩必须是有效的数字。", parent=self.master)
            return

        # 如果科目不存在，则创建
        if subject not in self.grades_data:
            self.grades_data[subject] = {}
        
        # 添加或更新成绩
        self.grades_data[subject][exam] = grade

        # 如果考试名称是新的，添加到考试列表中并排序
        if exam not in self.exams:
            self.exams.append(exam)
            # 保持考试顺序，可以按字母排序，或者更高级的自定义排序
            # 这里简单地按字母排序，如果需要按时间顺序，需要用户输入日期或更复杂的逻辑
            self.exams.sort() 

        messagebox.showinfo("成功", f"已添加: 科目 '{subject}', 考试 '{exam}', 成绩 {grade}", parent=self.master)
        
        # 清空输入框
        self.subject_entry.delete(0, tk.END)
        self.exam_entry.delete(0, tk.END)
        self.grade_entry.delete(0, tk.END)
        
        self.generate_chart() # 自动更新图表

    def generate_chart(self):
        """根据当前数据生成并显示走势图"""
        self.ax.clear() # 清除之前的绘图

        if not self.grades_data or not self.exams:
            # 如果没有数据，显示提示信息
            self.ax.text(0.5, 0.5, "暂无数据，请添加成绩点以生成走势图", 
                         horizontalalignment='center', verticalalignment='center', 
                         transform=self.ax.transAxes, fontsize=14, color='gray',
                         fontproperties='Microsoft YaHei')
            self.ax.set_title("成绩走势图", fontproperties='Microsoft YaHei', fontsize=16)
            self.ax.set_xlabel("考试", fontproperties='Microsoft YaHei', fontsize=12)
            self.ax.set_ylabel("成绩", fontproperties='Microsoft YaHei', fontsize=12)
            self.ax.set_ylim(0, 100) # 即使没有数据也设置Y轴范围
            self.ax.grid(True)
            self.canvas.draw()
            return

        # 准备绘图数据
        for subject, exam_grades in self.grades_data.items():
            grades_for_plot = []
            for exam in self.exams:
                # 如果某个科目在某个考试中没有成绩，使用np.nan，matplotlib会自动处理为断点
                grades_for_plot.append(exam_grades.get(exam, np.nan)) 

            self.ax.plot(self.exams, grades_for_plot, marker='o', label=subject)

        self.ax.set_title("成绩走势图", fontproperties='Microsoft YaHei', fontsize=16)
        self.ax.set_xlabel("考试", fontproperties='Microsoft YaHei', fontsize=12)
        self.ax.set_ylabel("成绩", fontproperties='Microsoft YaHei', fontsize=12)
        self.ax.set_ylim(0, 100) # 设置Y轴范围为0-100
        self.ax.legend(prop={'family':'Microsoft YaHei', 'size':10}) # 显示图例（科目名称），设置字体
        self.ax.grid(True) # 显示网格
        self.fig.autofmt_xdate() # 自动调整X轴标签，防止重叠

        self.canvas.draw() # 刷新Tkinter中的图表

    def clear_all_data(self):
        """清除所有成绩数据"""
        if messagebox.askyesno("确认清除", "确定要清除所有成绩数据吗？此操作不可撤销。", parent=self.master):
            self.grades_data = {}
            self.exams = []
            self.generate_chart() # 更新图表以显示空状态
            messagebox.showinfo("清除成功", "所有成绩数据已清除。", parent=self.master)

# 主程序入口
if __name__ == "__main__":
    root = tk.Tk()
    app = GradeTrendApp(root)
    root.mainloop()