如何使用openpyxl修改Excel工作表格式且保留原有样式?
解决openpyxl修改单元格格式时原有格式被重置的问题
你的问题出在每次给cell.font赋值全新的Font实例,这会完全覆盖单元格原有的字体属性——没在新Font里指定的属性会使用默认值(比如默认bold=False),所以之前设置的加粗效果会丢失。
核心解决方案
基于单元格已有字体属性,仅修改需要变更的部分,而不是直接替换整个Font对象。具体来说,先获取单元格当前的Font对象,复制其所有属性,再覆盖需要修改的参数,最后赋值回单元格。
修改后的完整代码
from openpyxl import load_workbook from openpyxl.styles import Font, Color, PatternFill, Border, Side def bold_italic(wb, ws, path, rows=None, cols=None, bold=None, italic=None): # 应用格式的内部函数 def apply_format(cell_range): for row in cell_range: for cell in row: # 获取单元格现有字体属性 existing_font = cell.font # 基于原有属性创建新字体,仅修改指定参数 new_font = Font( name=existing_font.name, size=existing_font.size, color=existing_font.color, bold=bold if bold is not None else existing_font.bold, italic=italic if italic is not None else existing_font.italic, underline=existing_font.underline, strike=existing_font.strike, vertAlign=existing_font.vertAlign, outline=existing_font.outline, shadow=existing_font.shadow, condense=existing_font.condense, extend=existing_font.extend ) cell.font = new_font # 处理行格式 if rows: if isinstance(rows, int): apply_format(ws.iter_rows(min_row=rows, max_row=rows)) elif isinstance(rows, list): for row in rows: apply_format(ws.iter_rows(min_row=row, max_row=row)) # 处理列格式 if cols: if isinstance(cols, int): apply_format(ws.iter_cols(min_col=cols, max_col=cols)) elif isinstance(cols, list): for col in cols: apply_format(ws.iter_cols(min_col=col, max_col=col)) wb.save(path) def font_size_color(wb, ws, path, rows=None, cols=None, font_name=None, font_size=None, font_color=None): # 应用字体格式的内部函数 def apply_font(cell_range): for row in cell_range: for cell in row: # 获取单元格现有字体属性 existing_font = cell.font # 基于原有属性创建新字体,仅修改指定参数 new_font = Font( name=font_name if font_name is not None else existing_font.name, size=font_size if font_size is not None else existing_font.size, color=font_color if font_color is not None else existing_font.color, bold=existing_font.bold, italic=existing_font.italic, underline=existing_font.underline, strike=existing_font.strike, vertAlign=existing_font.vertAlign, outline=existing_font.outline, shadow=existing_font.shadow, condense=existing_font.condense, extend=existing_font.extend ) cell.font = new_font # 处理行格式 if rows: if isinstance(rows, int): apply_font(ws.iter_rows(min_row=rows, max_row=rows)) elif isinstance(rows, list): for row in rows: apply_font(ws.iter_rows(min_row=row, max_row=row)) # 处理列格式 if cols: if isinstance(cols, int): apply_font(ws.iter_cols(min_col=cols, max_col=cols)) elif isinstance(cols, list): for col in cols: apply_font(ws.iter_cols(min_col=col, max_col=col)) wb.save(path) path = 'Book.xlsx' workbook = load_workbook(path) worksheet = workbook['SHEET_1'] bold_italic(workbook, worksheet, path, rows=2, cols=[2,3], bold=True) font_size_color(workbook, worksheet, path, rows=1, cols=[2,3], font_name='Arial', font_size=12, font_color="FF0000")
关键优化点说明
- 参数默认值调整:把函数参数的默认值从
False/具体值改成None,区分“用户明确要设置为False”和“用户不想修改该属性”两种场景。 - 继承原有属性:新Font对象完全复制原有字体的所有属性,仅替换用户指定的参数,确保原有格式不会丢失。
- 可进一步封装通用函数:为减少重复代码,可封装一个通用的字体更新函数:
def update_cell_font(cell, **kwargs): existing_font = cell.font # 收集原有属性,用传入的参数覆盖指定项 font_attrs = { 'name': existing_font.name, 'size': existing_font.size, 'color': existing_font.color, 'bold': existing_font.bold, 'italic': existing_font.italic, 'underline': existing_font.underline, 'strike': existing_font.strike, 'vertAlign': existing_font.vertAlign, 'outline': existing_font.outline, 'shadow': existing_font.shadow, 'condense': existing_font.condense, 'extend': existing_font.extend } font_attrs.update(kwargs) cell.font = Font(**font_attrs)
之后在内部函数里只需调用update_cell_font(cell, bold=bold, italic=italic)或update_cell_font(cell, name=font_name, size=font_size, color=font_color)即可,代码更简洁。
内容的提问来源于stack exchange,提问作者dcoolwater0502
相关产品推荐
相关产品推荐

