当前位置: 首页 > news >正文

gpt-4o继续迭代考场安排程序 一键生成考场清单

        接上两篇gpt-4o考场安排-CSDN博客,考场分层次安排,最终exe版-CSDN博客

当然你也可以只看这一篇。

今天又添加了以下功能,程序见后。

1、自动分页,每个考场打印一页

2、添加了打印试场单页眉

3、添加了页脚 第X页,其X页, 打印时间

表结构

程序运行界面

测试分配考场环境,共15个班分为两个层次由字段“层次”指定a, b。a层次9个考场,b层次15个,从b层开始编号,a层次考场号从16开编。

预览结果b层次

层次a预览结果

完整程序


import sysimport pandas as pdimport randomimport openpyxlfrom openpyxl.worksheet.pagebreak import Breakfrom openpyxl.styles import Font, Alignment, PatternFill, Border, Sidefrom openpyxl.worksheet.page import PageMarginsfrom datetime import datetimefrom PyQt5.QtWidgets import (QApplication, QLabel, QLineEdit, QPushButton, QFileDialog,QVBoxLayout, QWidget, QMessageBox)from PyQt5.QtGui import QFont as QPyQtFontdef load_data(filename):return pd.read_excel(filename)def save_data(df, filename, exam_name):df.to_excel(filename, index=False)format_excel(filename, df, exam_name)def assign_seats(df, total_halls, start_hall=1):grouped = df.groupby('班级')groups = [group.sample(frac=1).reset_index(drop=True) for _, group in grouped]groups.sort(key=lambda x: len(x), reverse=True)iterators = [iter(group.iterrows()) for group in groups]arranged_data = []hall_number = start_hallseat_number = 1total_students = len(df)students_per_hall = total_students // total_hallsextra_students = total_students % total_hallswhile iterators:random.shuffle(iterators)for it in iterators[:]:try:_, student = next(it)student_data = student.to_dict()student_data["考场"] = hall_numberstudent_data["考号"] = f"{seat_number:02d}"arranged_data.append(student_data)seat_number += 1if seat_number > students_per_hall + (1 if hall_number - start_hall + 1 <= extra_students else 0):hall_number += 1seat_number = 1if hall_number >= start_hall + total_halls:hall_number = start_hallexcept StopIteration:iterators.remove(it)return arranged_datadef check_and_adjust_seating(arranged_data):def has_adjacent_same_class(data):for i in range(len(data) - 1):if data[i]['班级'] == data[i + 1]['班级']:return ireturn -1def find_valid_swap(index, data):current_class = data[index]['班级']for j in range(len(data)):if j != index and data[j]['班级'] != current_class:if (j == 0 or data[j - 1]['班级'] != current_class) and (j == len(data) - 1 or data[j + 1]['班级'] != current_class):return jreturn -1swap_operations = []while True:index = has_adjacent_same_class(arranged_data)if index == -1:breakswap_index = find_valid_swap(index + 1, arranged_data)if swap_index == -1:raise ValueError("Cannot find a valid swap to adjust the seating arrangement.")swap_operations.append((index + 1, swap_index))arranged_data[index + 1], arranged_data[swap_index] = arranged_data[swap_index], arranged_data[index + 1]return arranged_data, swap_operationsdef reassign_seats(arranged_data, total_halls, start_hall=1):hall_number = start_hallseat_number = 1total_students = len(arranged_data)students_per_hall = total_students // total_hallsextra_students = total_students % total_hallsfor i, student in enumerate(arranged_data):student['考场'] = hall_numberstudent['考号'] = f"{seat_number:02d}"seat_number += 1if seat_number > students_per_hall + (1 if hall_number - start_hall + 1 <= extra_students else 0):hall_number += 1seat_number = 1if hall_number >= start_hall + total_halls:hall_number = start_hallreturn arranged_datadef format_excel(filename, df, exam_name):if '层次' in df.columns:df = df.drop(columns=['层次'])wb = openpyxl.Workbook()ws = wb.activews.title = "考场安排结果"# 将标题从第一行开始写入for col_num, column_title in enumerate(df.columns, 1):cell = ws.cell(row=1, column=col_num, value=column_title)cell.font = Font(bold=True, color="FFFFFF", size=16)cell.fill = PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid")cell.alignment = Alignment(horizontal="center", vertical="center")for row_num, row_data in enumerate(df.itertuples(index=False, name=None), 2):for col_num, cell_value in enumerate(row_data, 1):ws.cell(row=row_num, column=col_num, value=cell_value)for col in ws.columns:max_length = 0column = col[0].column_letter# Check if the column header is "考号"if ws.cell(row=1, column=col[0].col_idx).value == "考号":adjusted_width = 20  # 设置考号列的宽度为20else:for cell in col:if cell.value is not None:max_length = max(max_length, len(str(cell.value)))adjusted_width = max_length + 10ws.column_dimensions[column].width = adjusted_width# 调整页面边距ws.page_margins = PageMargins(left=1.5, right=0.75, top=1.2, bottom=0.5)ws.print_title_rows = '1:1'  # 标题行在第一行开始ws.page_setup.orientation = 'portrait'ws.page_setup.paperSize = ws.PAPERSIZE_A4ws.page_setup.fitToPage = Truews.page_setup.fitToWidth = 1ws.page_setup.fitToHeight = Falsews.page_setup.horizontalCentered = Truews.page_setup.verticalCentered = Truepage_height_in_inches = 11.69 - ws.page_margins.top - ws.page_margins.bottompage_height_in_points = page_height_in_inches * 72header_height_in_points = 50available_row_height_in_points = page_height_in_points - header_height_in_pointshall_groups = df.groupby('考场')previous_max_row = 1  # 前一个最大行号调整为1以考虑空行thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin'))for hall_number, (hall_id, hall_df) in enumerate(hall_groups):row_count = len(hall_df) + 1max_row = hall_df.index[-1] + 2  # 从第二行开始每个考场的数据row_height = available_row_height_in_points / row_countrow_height = max(row_height, 15)for row in range(previous_max_row, max_row + 1):ws.row_dimensions[row].height = row_heightfor cell in ws[row]:cell.border = thin_bordercell.font = Font(size=15)cell.alignment = Alignment(horizontal="center", vertical="center")if max_row < ws.max_row:ws.row_breaks.append(Break(max_row))previous_max_row = max_row + 1# 添加页眉和页脚,并使用制表符来向左移动页眉ws.oddHeader.center.text = f"&\"微软雅黑,Bold\"&20\t{exam_name}"  # 添加制表符以向左移动ws.oddFooter.center.text = "第 &P 页,共 &N 页"ws.oddFooter.right.text = f"&D &T"wb.save(filename)def dataframe_to_rows(df, index=True, header=True):if header:rows = [list(df.columns)]else:rows = [[]]for row in df.itertuples(index=index, name=None):rows.append(list(row)[1:])return rowsdef run_allocation(input_filename, a_total_halls, b_total_halls, start_level, exam_name):df = load_data(input_filename)if start_level == 'b':other_level = 'a'first_total_halls = b_total_hallssecond_total_halls = a_total_hallselse:other_level = 'b'first_total_halls = a_total_hallssecond_total_halls = b_total_hallsfirst_level_students = df[df['层次'] == start_level]arranged_first_students = assign_seats(first_level_students, first_total_halls, start_hall=1)adjusted_first_students, _ = check_and_adjust_seating(arranged_first_students)final_first_students = reassign_seats(adjusted_first_students, first_total_halls, start_hall=1)second_level_students = df[df['层次'] == other_level]arranged_second_students = assign_seats(second_level_students, second_total_halls, start_hall=first_total_halls + 1)adjusted_second_students, _ = check_and_adjust_seating(arranged_second_students)final_second_students = reassign_seats(adjusted_second_students, second_total_halls,start_hall=first_total_halls + 1)combined_students = final_first_students + final_second_studentsarranged_df = pd.DataFrame(combined_students)current_time = datetime.now().strftime("%Y%m%d_%H%M%S")output_filename = f"考场安排结果_{current_time}.xlsx"save_data(arranged_df, output_filename, exam_name)return output_filenameclass ExamArrangementApp(QWidget):def __init__(self):super().__init__()self.initUI()def initUI(self):layout = QVBoxLayout()font = QPyQtFont("Arial", 14)self.file_label = QLabel('选择文件:')self.file_label.setFont(font)layout.addWidget(self.file_label)self.file_btn = QPushButton('选择文件')self.file_btn.setFont(font)self.file_btn.clicked.connect(self.select_file)layout.addWidget(self.file_btn)self.exam_name_label = QLabel('考试名称:')self.exam_name_label.setFont(font)layout.addWidget(self.exam_name_label)self.exam_name_input = QLineEdit()self.exam_name_input.setFont(font)layout.addWidget(self.exam_name_input)self.a_halls_label = QLabel('A层次考场数:')self.a_halls_label.setFont(font)layout.addWidget(self.a_halls_label)self.a_halls_input = QLineEdit()self.a_halls_input.setFont(font)layout.addWidget(self.a_halls_input)self.b_halls_label = QLabel('B层次考场数:')self.b_halls_label.setFont(font)layout.addWidget(self.b_halls_label)self.b_halls_input = QLineEdit()self.b_halls_input.setFont(font)layout.addWidget(self.b_halls_input)self.start_level_label = QLabel('首先开始编号的层次 (a/b):')self.start_level_label.setFont(font)layout.addWidget(self.start_level_label)self.start_level_input = QLineEdit()self.start_level_input.setFont(font)layout.addWidget(self.start_level_input)self.run_btn = QPushButton('运行')self.run_btn.setFont(font)self.run_btn.clicked.connect(self.run)layout.addWidget(self.run_btn)self.setLayout(layout)self.setWindowTitle('考场安排工具,By Bobo googaobo@gmail.com')self.resize(900, 630)self.center()def select_file(self):options = QFileDialog.Options()options |= QFileDialog.DontUseNativeDialogfile_name, _ = QFileDialog.getOpenFileName(self, "选择Excel文件", "", "Excel Files (*.xlsx);;All Files (*)",options=options)if file_name:self.file_label.setText(f'文件: {file_name}')self.input_filename = file_namedef run(self):try:a_total_halls = int(self.a_halls_input.text())b_total_halls = int(self.b_halls_input.text())start_level = self.start_level_input.text()exam_name = self.exam_name_input.text()output_filename = run_allocation(self.input_filename, a_total_halls, b_total_halls, start_level, exam_name)QMessageBox.information(self, "成功", f"已成功生成文件:{output_filename}", QMessageBox.Ok)except Exception as e:QMessageBox.critical(self, "错误", str(e), QMessageBox.Ok)def center(self):qr = self.frameGeometry()cp = self.screen().availableGeometry().center()qr.moveCenter(cp)self.move(qr.topLeft())if __name__ == '__main__':app = QApplication(sys.argv)ex = ExamArrangementApp()ex.show()sys.exit(app.exec_())

程序已打包exe,点赞留言QQ,发送程序。程序运行中有问题请评论区留言交流!!!

http://www.lryc.cn/news/358419.html

相关文章:

  • php 设置时区
  • ArcGIS不同图斑设置不同的透明度
  • 前端 CSS 经典:图片边框
  • 异常有什么,异常类有什么
  • 如何解压忘记了密码的加密zip压缩包?这两个方法收藏好!
  • java中,怎样用最简单方法实现写word文档
  • 大语言模型的工程技巧(三)——分布式计算
  • AI开发初体验:昇腾加持,OrangePi AIpro 开发板
  • 微服务架构下Docker容器技术与Kubernetes(K8S)
  • 风萧萧兮易水寒,壮士一去兮不复还 的 rm 命令
  • How Diffusion Models Work
  • antd table列选中效果实现
  • Golang实现文件复制
  • 探秘SpringBoot默认线程池:了解其运行原理与工作方式(@Async和ThreadPoolTaskExecutor)
  • kubernetes(Jenkins、kubernetes核心、K8s实战-KubeSphere、)
  • 国际数字影像产业园|科技与文创产品创意集市,共筑创新文化新高地
  • leetcode-55 跳跃游戏
  • Vue——计算属性 computed 与方法 methods 区别探究
  • Java中的ORM框架——myBatis
  • vue2生命周期和计算属性
  • Hadoop3:MapReduce之简介、WordCount案例源码阅读、简单功能开发
  • centos8stream 编译安装 php-rabbit-mq模块
  • 「异步魔法:Python数据库交互的革命」(二)
  • php正则中的i,m,s,x,e分别表示什么
  • 最新!2023年台湾10米DEM地形瓦片数据
  • 网络学习(11) |深入解析客户端缓存与服务器缓存:HTTP缓存控制头字段及优化实践
  • uniapp中二次封装jssdk和使用
  • 只刷题可以通过PMP考试吗?
  • Python Selenium 详解:实现高效的UI自动化测试
  • npm获取yarn在安装依赖时 git://github.com/user/xx.git 无法访问解决方法 -- 使用 insteadOf设置git命令别名