Bootstrap

某学校成绩分析代码

import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import pandas as pd
import math

# 全局变量存储文件路径
file_path = None
results_df = pd.DataFrame(columns=['年级', '班级', '语文', '数学', '英语', '语文教师', '数学教师', '英语教师'])

def open_file():
    """ 打开文件并存储路径 """
    global file_path
    file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
    if file_path:
        status_label.config(text=f"已选择文件: {file_path}")
    else:
        status_label.config(text="未选择任何文件")

def calculate_averages():
    """ 计算平均分并写入新表 """
    global results_df
    if not file_path:
        messagebox.showerror("错误", "请先选择成绩表")
        return

    try:
        # 使用 xlrd 读取 Excel 文件
        xls = pd.ExcelFile(file_path)
        sheets = xls.sheet_names

        # 创建新的 DataFrame 来存储结果
        results_df = pd.DataFrame(columns=['年级', '班级', "人数",'语文', '语文教师', '数学', '数学教师', '英语', '英语教师'])

        # 获取教师任课表
        teacher_sheet = None
        for sheet in sheets:
            if '教师任课表' in sheet:
                teacher_sheet = pd.read_excel(xls, sheet_name=sheet)
                break

        if teacher_sheet is None:
            raise ValueError("缺少教师任课表,请检查文件")

        # 处理每个工作表
        for sheet in sheets:
            if '教师任课表' in sheet:
                continue

            df = pd.read_excel(xls, sheet_name=sheet)

            # 确保所需列存在
            required_columns = ['年级', '班级', '语文', '数学', '英语']
            if not all(col in df.columns for col in required_columns):
                raise ValueError(f"缺少必要列,请检查{sheet}表")

            # 按年级班级分组
            grouped = df.groupby(['年级', '班级'])

            # 替换空值为 0
            df[required_columns[2:]] = df[required_columns[2:]].fillna(0)

            for (grade, class_), group in grouped:
                num_students = len(group)
                if checkbox_var.get():
                    num=math.floor(num_students * 0.08)
                    print("扣除:",num)
                else:
                    num=0
                    print("扣除:",num)
                exclude_num = max(0, int(num))  # 至少排除一人

                # 计算去除最低分后的平均分
                avg_scores = group[required_columns[2:]].apply(
                    lambda x: x.nlargest(num_students - exclude_num).mean(), axis=0)

                # 提取教师信息
                chinese_teacher = get_teacher_name(teacher_sheet, grade, class_, '语文')
                math_teacher = get_teacher_name(teacher_sheet, grade, class_, '数学')
                english_teacher = get_teacher_name(teacher_sheet, grade, class_, '英语')

                # 添加到结果 DataFrame
                result_row = pd.DataFrame({
                    '年级': [grade],
                    '班级': [class_],
                    '人数':[num_students],
                    '语文': [avg_scores['语文']],
                    '数学': [avg_scores['数学']],
                    '英语': [avg_scores['英语']],
                    '语文教师': [chinese_teacher],
                    '数学教师': [math_teacher],
                    '英语教师': [english_teacher]
                })
                # 在拼接之前,检查并删除全是 NA 的列
                result_row = result_row.dropna(axis=1, how='all')
                results_df = pd.concat([results_df, result_row], ignore_index=True)

        # 更新结果显示表格
        update_results_table(results_df)

        # 写入新表
        # with pd.ExcelWriter(file_path, mode='a', engine='openpyxl') as writer:
        #     results_df.to_excel(writer, sheet_name='计算表', index=False)
        #
        # messagebox.showinfo("成功", "计算完成并已保存至新表")

    except Exception as e:
        messagebox.showerror("错误", f"发生错误: {str(e)}")

def get_teacher_name(teacher_sheet, grade, class_, subject):
    """ 从教师任课表中获取指定年级班级和科目的教师姓名 """
    row = teacher_sheet[(teacher_sheet['年级'] == grade) & (teacher_sheet['班级'] == class_)]
    if not row.empty:
        return row[subject].iloc[0]
    return ""


def update_results_table(df):
    """ 更新结果显示表格 """
    # 清除旧数据
    results_treeview.delete(*results_treeview.get_children())

    # 获取 DataFrame 的列标题
    columns = list(df.columns)

    # 重新配置 Treeview 的列标题和显示的列
    results_treeview.config(columns=columns)

    # 为每一列设置标题和宽度
    for col in columns:
        results_treeview.heading(col, text=col)

        # 根据列名设置合理宽度
        if '名次' in col :
            results_treeview.column(col, width=40, stretch=False)  # 名次与分差列宽度较小
        elif '教师' in col:
            results_treeview.column(col, width=60, stretch=False)  # 教师列
        elif '平均分' in col or '分差' in col:
            results_treeview.column(col, width=100, stretch=False)  # 其他列
        else:
            results_treeview.column(col, width=40, stretch=False)  # 其他列宽度较小

    # 插入新的数据
    for index, row in df.iterrows():
        results_treeview.insert('', 'end', values=row.tolist())


def save_results():
    """ 另存结果显示表格中的数据到新文件 """
    global results_df
    if results_df.empty:
        messagebox.showerror("错误", "没有计算结果可以保存")
        return

    new_file_path = filedialog.asksaveasfilename(defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx")])
    if not new_file_path:
        return

    try:
        results_df.to_excel(new_file_path, index=False)
        messagebox.showinfo("成功", "结果已保存至新文件")
    except Exception as e:
        messagebox.showerror("错误", f"保存失败: {str(e)}")

def calculate_rank_and_diff():
    """ 计算名次与分差 """
    global results_df

    if results_df.empty:
        messagebox.showerror("错误", "没有可供计算的数据")
        return

    def calculate_for_subject(df, subject_col):
        """ 按学科列计算名次和分差 """
        for grade in df['年级'].unique():
            grade_df = df[df['年级'] == grade].copy()
            sorted_df = grade_df.sort_values(by=subject_col, ascending=False)

            sorted_df['名次'] = range(1, len(sorted_df) + 1)
            max_score = sorted_df[subject_col].iloc[0]
            sorted_df['分差'] = sorted_df[subject_col] - max_score

            df.loc[df['年级'] == grade, f'{subject_col}名次'] = sorted_df['名次']
            df.loc[df['年级'] == grade, f'{subject_col}分差'] = sorted_df['分差']

    # 计算各科目的名次和分差
    calculate_for_subject(results_df, '语文')
    calculate_for_subject(results_df, '数学')
    calculate_for_subject(results_df, '英语')

    # 调整列顺序,将名次和分差列插入到相应的“平均分”列后面
    columns_order = [
        '年级', '班级', '人数',
        '语文教师',
        '语文', '语文名次', '语文分差',
        '数学教师',
        '数学', '数学名次', '数学分差',
        '英语教师',
        '英语', '英语名次', '英语分差'
    ]

    results_df = results_df[columns_order]

    # 更新结果显示表格
    update_results_table(results_df)

# 创建主窗口
root = tk.Tk()
root.title("中心小学成绩表处理工具")
root.geometry("1000x800")  # 固定窗口大小

# 按钮布局
button_frame = tk.Frame(root)
button_frame.pack(pady=10)
# 添加一个多选框,默认为不选中
checkbox_var = tk.BooleanVar()  # 使用 BooleanVar 跟踪状态
checkbox_var.set(False)  # 设置初始状态为未选中

checkbox = tk.Checkbutton(root, text="扣除人数", variable=checkbox_var)
checkbox.pack(pady=5)

open_button = tk.Button(button_frame, text="打开成绩表", command=open_file)
open_button.pack(side=tk.LEFT, padx=5)

calculate_button = tk.Button(button_frame, text="开始计算", command=calculate_averages)
calculate_button.pack(side=tk.LEFT, padx=5)





# 添加新的按钮用于名次与分差计算
rank_diff_button = tk.Button(button_frame, text="名次与分差", command=calculate_rank_and_diff)
rank_diff_button.pack(side=tk.LEFT, padx=5)

save_button = tk.Button(button_frame, text="结果另存", command=save_results)
save_button.pack(side=tk.LEFT, padx=5)

status_label = tk.Label(root, text="")
status_label.pack(pady=10)

# 结果显示表格和滚动条
tree_frame = tk.Frame(root)
tree_frame.pack(fill=tk.BOTH, expand=True)

# 创建滚动条
# 创建结果显示表格
results_treeview = ttk.Treeview(tree_frame, columns=['年级', '班级', '人数', '语文教师','语文', '语文名次', '语文分差', '数学教师','数学', '数学名次', '数学分差', '英语教师' '英语', '英语名次', '英语分差' ], show='headings')
for col in results_treeview['columns']:
    results_treeview.heading(col, text=col)
    results_treeview.column(col, width=100)

# 创建滚动条
scroll_y = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL, command=results_treeview.yview)
scroll_x = ttk.Scrollbar(tree_frame, orient=tk.HORIZONTAL, command=results_treeview.xview)

# 配置滚动条
results_treeview.configure(yscrollcommand=scroll_y.set, xscrollcommand=scroll_x.set)
#
# # 设置 Treeview
# results_treeview = ttk.Treeview(tree_frame, columns=['年级', '班级', '人数', '语文平均分', '语文教师', '数学平均分', '数学教师', '英语平均分', '英语教师'],
#                                 show='headings',
#                                 yscrollcommand=scroll_y.set,
#                                 xscrollcommand=scroll_x.set)
#
# # 设置每列宽度
# for col in results_treeview['columns']:
#     results_treeview.heading(col, text=col)
#     results_treeview.column(col, width=150, stretch=False)
# scroll_y = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL, command=results_treeview.yview)
# scroll_x = ttk.Scrollbar(tree_frame, orient=tk.HORIZONTAL, command=results_treeview.xview)
#
#

# 将滚动条与 Treeview 绑定
scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
results_treeview.pack(fill=tk.BOTH, expand=True)

# 设置 Treeview 样式
style = ttk.Style()
style.configure('Treeview', rowheight=30, fieldbackground='grey', background='white', borderwidth=4, relief='solid')

# 运行主循环
root.mainloop()

;