背景需求:

为了发被子,我做了全校批量的圆形挂牌,可以绑在“被子包”提手上,便于再操场上发放被子时,很多老师可以协助根据学号发放。

https://blog.csdn.net/reasonsummer/article/details/149755556?spm=1011.2415.3001.5331https://blog.csdn.net/reasonsummer/article/details/149755556?spm=1011.2415.3001.5331

 没想到,除了被子提示,领导和班主任还拓展出“家长接孩子排队卡”“床卡”“入园卡”的功能。

但是问题也随之出现。9月1-8日,中班陆续插了6位孩子。班主任需要新孩子的“圆牌”“长方挂牌卡”。可是由于我做的PDF版本,而且内容本身就是图片(做成图片插入docx),

所以班主任自己改不了。就只能找我来修改。

(点名册已经做了PDF和excle编辑版,所以班主任没有索要)

因为我也带班,所以要放学才能看到消息,然后再用程序批量做,虽然我尝试只批量几个班级(中班),但这只是快了一点点时间,加上发送,耗费我的精力和时间(来一个批量一次,很琐碎。对班主任来说,无法及时获取打印素材,增加焦虑感(这个任务实在很小,但是很需要)。

所以必须做一个班主任自己可以编辑的圆牌和长方牌版本,后续就不用我再反复修改了。

设计过程

1,模板展位:

我尝试了”形状圆形+文本框文字”,但是deepseek写了几十次代码,都无法把文本框文字合并到一起,最终会缺少或者重叠。

单个docx可以

但是无法合并在一个docx里(即时能合并,也不能保证一页撑满6图,因为这是文本框,会动来动去的)

2、图片浮于文字下方

在2列3行里插入空白圆形背景图片

插入图片后,光标就移到顶部中间,我设置了浮于文字下方,但是因为是在表格里,所以默认图片占了位置。

如果按回车,文字和图片会一起向下

以上两种都不行,最后我只能考虑word插入背景图

3、word背景图

将第2次测试的模板图案(图片浮于文字上方+隐藏边框)全部复制到ppt,做成图片

这个图片差不多就是A4-0.7CM边距的大小。

再贴一个A4大小的蓝色背景做区分

原始word,插入2*3,边框隐藏

再设计里面找到页面颜色

选“纹理”,不是'图片"(图片做背景会填充,就有10-18个圆)

此时,六个圆形是背景图,不占文字的位置,所以单元格的光标都上下左右居中。

然后蓝色填充白色,这样就是和A4一样大小的白色背景图

代码部分(4次优化)

1、制作一个班级的基础模板

6个分组保存一个docx,把第2:5的docx的内容用win32原样复制到第1个docx里,用第1个背景图和框架。

今天大部分时间都遇到“合并出错”

文字的位置:通过反复的计算,确定每个文字的大小,间距、灰度。

# -*- coding:utf-8 -*-
'''
制作被子圆牌(word合并)一个班级
预先再word里面页面背景-纹理,插入A4大小的图片背景(有6个园),
deepseek,豆包 阿夏
20250913'''
import os
import pandas as pd
from docx import Document
from docx.shared import Cm
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.shared import Pt  # 用于设置字体大小
from docx.oxml.ns import qn  # 用于设置中文字体
from pypinyin import pinyin, Style
from docx.enum.table import WD_CELL_VERTICAL_ALIGNMENT
from docx.shared import RGBColor  # 用于设置字体颜色
import shutil# ========== 1. 核心配置(仅修改此部分路径) ==========
base_dir = r'c:\Users\jg2yXRZ\OneDrive\桌面\20250913文本框可编辑全校被子挂牌'
excel_file = os.path.join(base_dir, "班级信息表.xlsx")  # Excel数据路径
template_word = os.path.join(base_dir, "挂牌.docx")     # 现有3行2列表格模板
output_dir = os.path.join(base_dir, "小2班挂牌结果")     # 结果保存目录
editable_dir = os.path.join(base_dir, "word可编辑文件夹")  # 新建的可编辑文件夹
os.makedirs(output_dir, exist_ok=True)  # 创建结果目录
os.makedirs(editable_dir, exist_ok=True)  # 创建可编辑文件夹# ========== 2. Excel数据读取与拼音生成(保留核心逻辑) ==========
def read_excel_and_generate_pinyin(file_path):"""读取Excel数据,生成带声调的姓名拼音,返回{班级名: 学生数据列表}"""# 特殊姓氏读音校正(确保拼音准确性)SPECIAL_SURNAMES = {"乐": "Yuè", "单": "Shàn", "解": "Xiè", "查": "Zhā","盖": "Gě", "仇": "Qiú", "种": "Chóng", "朴": "Piáo","翟": "Zhái", "区": "Ōu", "繁": "Pó", "覃": "Qín","召": "Shào", "华": "Huà", "纪": "Jǐ", "曾": "Zēng","缪": "Miào", "员": "Yùn", "车": "Chē", "过": "Guō","尉": "Yù", "万": "Wàn"}COMPOUND_SURNAMES = {"欧阳": "Ōu yáng", "上官": "Shàng guān", "皇甫": "Huáng fǔ","尉迟": "Yù chí", "万俟": "Mò qí", "长孙": "Zhǎng sūn","司徒": "Sī tú", "司空": "Sī kōng", "司马": "Sī mǎ","诸葛": "Zhū gě", "东方": "Dōng fāng", "独孤": "Dú gū","慕容": "Mù róng", "宇文": "Yǔ wén"}def correct_name_pinyin(name):"""生成带声调的姓名拼音(姓氏校正)"""if not name or not isinstance(name, str):return ""name = name.strip()# 优先处理复姓for compound_surn in COMPOUND_SURNAMES:if name.startswith(compound_surn):surn_pinyin = COMPOUND_SURNAMES[compound_surn]given_name = name[len(compound_surn):]given_pinyin = ' '.join([p[0] for p in pinyin(given_name, style=Style.TONE)])return f"{surn_pinyin} {given_pinyin}"# 处理单姓多音字first_char = name[0]if first_char in SPECIAL_SURNAMES:surn_pinyin = SPECIAL_SURNAMES[first_char]given_name = name[1:]given_pinyin = ' '.join([p[0] for p in pinyin(given_name, style=Style.TONE)])return f"{surn_pinyin} {given_pinyin}"# 普通姓名拼音return ' '.join([p[0] for p in pinyin(name, style=Style.TONE)])try:# 只读取小2班工作表df = pd.read_excel(file_path, sheet_name="小2班", usecols=range(5), header=None, dtype={0: str})df = df.iloc[1:]  # 跳过第1行标题student_list = []for idx, row in df.iterrows():# 过滤无效数据(学号为空、姓名为空)raw_id = str(row[0]).strip() if pd.notna(row[0]) else ""name = str(row[3]).strip() if pd.notna(row[3]) else ""if not raw_id.isdigit() or not name:continue# 提取核心信息student_info = {"campus": "XXX幼(" + (str(row[1]).strip() if pd.notna(row[1]) else "") + ")",  # 园区"class_name": str(row[2]).strip() if pd.notna(row[2]) else "",  # 班级"student_id": f"{int(raw_id)}号",  # 学号(如:1号)"name": name,  # 姓名"name_pinyin": correct_name_pinyin(name)  # 带声调拼音}student_list.append(student_info)if student_list:print(f"读取[小2班]:{len(student_list)}个有效学生")return {"小2班": student_list}return {}except Exception as e:print(f"Excel读取失败:{str(e)}")return {}# ========== 3. 写入Word表格(3行2列,单个单元格含5种信息+回车) ==========
def write_student_to_word(student_list, template_path, output_path, class_name):"""将学生数据写入Word模板的3行2列表格单个单元格内容:园区\n班级\n学号\n拼音\n姓名(按此顺序换行)字体:微软雅黑;拼音大小:10pt;姓名大小:20pt;其他信息:14pt颜色:班级、拼音、姓名为灰色,学号为黑色"""# 按6个学生一组分割(3行2列表格可容纳6个学生)student_groups = [student_list[i:i+6] for i in range(0, len(student_list), 6)]generated_files = []  # 存储生成的文件路径for group_idx, group in enumerate(student_groups, 1):# 复制模板文件(避免修改原模板)temp_template = os.path.join(output_path, f"temp_{group_idx}.docx")shutil.copy2(template_path, temp_template)# 打开复制后的模板,操作表格doc = Document(temp_template)# 获取模板中的第一个表格(需确保"挂牌2.docx"的第一个表格是3行2列")if not doc.tables:print(f"模板{template_path}中未找到表格,跳过此组")os.remove(temp_template)continuetable = doc.tables[0]# 清除表格原有内容for row in table.rows:for cell in row.cells:for para in cell.paragraphs:p = para._elementp.getparent().remove(p)cell._element.clear()  # 完全清空单元格# 定义字体样式def set_paragraph_style(para, text, font_size, is_bold=False, is_gray=True, underline=False):"""设置段落的字体、大小、对齐(居中)和颜色"""if not text:  # 跳过空文本returnrun = para.add_run(text)# 设置中文字体为微软雅黑run.font.name = '微软雅黑'run.element.rPr.rFonts.set(qn('w:eastAsia'), '微软雅黑')run.font.size = Pt(font_size)run.font.bold = is_boldrun.font.underline = underline  # 设置下划线# 设置颜色:灰色或黑色if is_gray:run.font.color.rgb = RGBColor(169, 169, 169)  # DarkGrayelse:run.font.color.rgb = RGBColor(0, 0, 0)  # 黑色para.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 文字居中# 逐个单元格写入学生信息(3行2列,共6个单元格)cell_index = 0  # 单元格索引(0-5对应3行2列的6个单元格)for row_idx, row in enumerate(table.rows):for cell_idx, cell in enumerate(row.cells):if cell_index >= len(group):break  # 学生不足6个时,空单元格跳过# 添加这行代码:设置单元格垂直居中cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER# 当前学生的5种信息(按"园区→班级→学号→拼音→姓名"顺序")student = group[cell_index]info_lines = [student["campus"],          # 第1行:园区student["class_name"],      # 第2行:班级student["student_id"],      # 第3行:学号student["name_pinyin"],     # 第4行:拼音(10pt)student["name"]             # 第5行:姓名(20pt,加粗)]# 向单元格写入内容(每行单独设置字体大小和颜色)for line_idx, line in enumerate(info_lines):if line:  # 只写入非空内容para = cell.add_paragraph()if line_idx == 0:  # 园区:16ptset_paragraph_style(para, line, font_size=16, is_bold=True, is_gray=True)para.paragraph_format.line_spacing = Pt(30)elif line_idx == 1:  # 班级:30ptset_paragraph_style(para, line, font_size=30, is_bold=True, is_gray=True)para.paragraph_format.line_spacing = Pt(40)elif line_idx == 2:  # 学号:50ptset_paragraph_style(para, line, font_size=50, is_bold=True, is_gray=False, underline=True)para.paragraph_format.line_spacing = Pt(65)elif line_idx == 3:  # 拼音行:10ptset_paragraph_style(para, line, font_size=10, is_bold=True, is_gray=True)para.paragraph_format.line_spacing = Pt(25)elif line_idx == 4:  # 姓名行:30pt,加粗set_paragraph_style(para, line, font_size=30, is_bold=True, is_gray=True)para.paragraph_format.line_spacing = Pt(35)cell_in

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/922222.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/922222.shtml
英文地址,请注明出处:http://en.pswp.cn/news/922222.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Shoptnt 促销计算引擎详解:策略模式与责任链的完美融合

在电商系统中,促销计算是业务逻辑最复杂、变更最频繁的模块之一。它不仅需要处理多种促销类型(满减、折扣、优惠券等),还要管理它们之间的优先级和互斥关系。 Shoptnt 设计了一套基于 策略模式 (Strategy Pattern) 和 责任链模式…

【HTTP 请求格式】从请求行 到 请求体

引言 在前后端开发中,前端和后端之间的交互主要依赖于 HTTP(HyperText Transfer Protocol,超文本传输协议)。HTTP 是互联网通信的基础,它定义了客户端(通常是浏览器或App)和服务器之间如何交换数…

【自记】SQL 中 GROUPING 和 GROUPING SETS 语句的案例说明

我们用一个生活中的例子来理解,比如你开了家小超市,想统计「销售额」,但需要从多个角度看(比如按 “日期 商品”、“仅日期”、“仅商品”、“整体总销售额”)。假设你的销售数据长这样(简化版&#xff09…

C语言第五课:if、else 、if else if else 控制语句

C语言第五课&#xff1a;if、else 、if else if else 控制语句if else 、if else if else 联合使用编程快速学习平台if else 、if else if else 联合使用 代码示列 #include <stdio.h> int main(){//设置中文编码输出到控制台system("chcp 65001");//今天星…

七彩喜智慧养老:用科技温暖晚年,让关爱永不掉线

“当银发潮遇见科技力&#xff0c;养老方式正在发生一场静悄悄的变革。”你有没有想过&#xff1a;当父母年迈独居时&#xff0c;如何确保他们的安全&#xff1f;当老人突然摔倒&#xff0c;如何第一时间获得救助&#xff1f;当慢性病需要长期管理&#xff0c;如何避免频繁奔波…

window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(二)

显示相关的 API 的比较 API用途和目标受众DisplayInformation用于检索 CoreWindow 的呈现和布局属性。HdmiDisplayInformation用于枚举和设置受限模式集的仅限 Xbox 的 API。 高度专用于 Xbox 媒体应用方案。DisplayMonitor用于查询物理监视器设备的属性。 不公开有关操作系统…

Linux 高性能 I/O 事件通知机制的核心系统调用—— `epoll_ctl`

epoll 是 Linux 上处理大量文件描述符 I/O 事件的高效模型&#xff0c;而 epoll_ctl 则是你用来指挥 epoll 实例&#xff08;epoll instance&#xff09;的“遥控器”&#xff0c;负责向它添加、修改或删除需要监视的文件描述符&#xff08;FD&#xff09;及其感兴趣的事件。1.…

mysql 必须在逗号分隔字符串和JSON字段之间二选一,怎么选

如果必须在逗号分隔字符串和JSON字段之间二选一&#xff0c;那么 JSON字段是明显更好的选择。以下是详细的对比分析&#xff1a;对比结论&#xff08;直接看这里&#xff09;方面JSON字段逗号分隔字符串胜出方查询能力✅ 丰富的JSON函数支持❌ 只能使用LIKE模糊查询JSON数据验证…

DPI和DIP的区别

DPI 和 DIP 是两个在计算机图形和移动开发领域常见的术语&#xff0c;它们都与屏幕显示和尺寸有关&#xff0c;但含义和用途不同。 DPI (Dots Per Inch) 定义&#xff1a;DPI 的全称是 Dots Per Inch&#xff0c;即每英寸点数。它是一个衡量物理密度的单位&#xff0c;表示在…

数据帮助我们理解未知世界

主持人 尼古拉安根&#xff1a; 大家好&#xff0c;我是挪威南方财富基金首席执行官尼古拉安根。今天非常荣幸能与大卫斯皮格尔哈尔特爵士对话。坦率地说&#xff0c;他不仅是世界上最优秀的统计学家之一&#xff0c;也是我见过的最佳风险沟通者。他撰写了大量优秀著作&#xf…

在使用git的很多操作是保持工作区干净

这是一条铁律下面是错误操作&#xff1a;自己明明写完了代码&#xff0c;想要提交。此时你的工作区长这样你的提交顺序是&#xff1a;git pull -> git commit -> git push但是现实往往不这样&#xff0c;万一拉下来的代码和你当前工作区的代码有冲突&#xff0c;你必须要…

通过语法推导树快速求短语,简单短语和句柄

第一步&#xff1a;写出规范推导&#xff08;最右&#xff09;序列 规范推导就是最右推导。我们的目标是从起始符号 E 出发&#xff0c;通过每步替换最右边的非终结符&#xff0c;最终得到句型 R(Pi)。 文法 G[E]: E :: RP | PP :: (E) | iR :: RP | RP* | P | P* 推导过程&…

智能学习辅助系统-部门管理开发

文章目录准备工作工程搭建增删改查查询部门删除部门新增部门修改部门查询回显修改数据日志技术准备工作 需求&#xff1a;部门管理的查询、新增、修改、删除 使用REST风格的URL&#xff1a; GET &#xff1a; 查询POST &#xff1a;新增PUT &#xff1a; 修改DELETE &#x…

【图解】idea中快速查找maven冲突

现象 今天启动项目时&#xff0c;总是以下报错&#xff0c;并退出SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/F:/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.13.3/log4j-slf4j-impl-2.13.3.jar!/org/slf4j/im…

LightGBM、XGBoost和CatBoost自定义损失函数和评估指标

LightGBM、XGBoost和CatBoost自定义损失函数和评估指标函数&#xff08;缩放误差&#xff09;数学原理损失函数定义梯度计算评估指标LightGBM实现自定义损失函数自定义评估指标使用方式XGBoost实现自定义损失函数自定义评估指标使用方式CatBoost实现自定义损失函数自定义评估指…

2025-09-08升级问题记录: 升级SDK从Android11到Android12

将 Android 工程的 targetSdkVersion 从 30 &#xff08;Android 11&#xff09;升级到 31&#xff08;Android 12&#xff09;需要关注一些重要的行为变更和适配点。 主要适配要点&#xff1a; 适配类别关键变更点适配紧迫性简要说明组件导出属性声明了 Intent Filter 的组件…

利用OpenCV实现模板与多个对象匹配

代码实现&#xff1a;import cv2 import numpy as npimg_rgb cv2.imread(mobanpipei.jpg) img_gray cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY) template cv2.imread(jianto.jpg, flags0) h, w template.shape[:2]# 读取图像# # 顺时针旋转 90 度&#xff08;k1&#xff0…

OS28.【Linux】自制简单的Shell的修bug记录

目录 1.问题代码 2.排查 前期检查 查找是谁修改了environ[0] 使用gdb下断点 查看后续的影响 分析出问题的split_commandline函数 3.反思 4.正确代码 5.结论 6.除此之外...... ★提示: 此bug非常隐蔽,不仔细分析很难查出问题,非常锻炼调试能力! 1.问题代码 #includ…

Debian 系统上安装与配置 MediaMTX

&#x1f3af; 在 Debian 系统上安装与配置 MediaMTX&#xff08;原 rtsp-simple-server&#xff09;&#xff1a;打造轻量级流媒体服务器 作者&#xff1a;远在太平洋 环境&#xff1a;Debian 10/11/12 | Ubuntu 可参考 关键词&#xff1a;MediaMTX、rtsp-simple-server、RTSP…

分布式专题——10.4 ShardingSphere-Proxy服务端分库分表

1 为什么要有服务端分库分表&#xff1f; ShardingSphere-Proxy 是 ShardingSphere 提供的服务端分库分表工具&#xff0c;定位是“透明化的数据库代理”。 它模拟 MySQL 或 PostgreSQL 的数据库服务&#xff0c;应用程序&#xff08;Application&#xff09;只需像访问单个数据…