Losing merged cells border while editing Excel file with openpyxl
我在Excel文件中有两张纸,第一张是我不需要编辑的封面。封面中有一些合并的单元格,当我使用openpyxl编辑文件时,甚至不接触封面,我就失去了合并单元格的边界。我正在使用
有什么办法可以解决此问题?
实际的解决方案是在包含库之后通过包含此代码片段来修补库代码,从而解决了该问题。 (注意:不要担心缺少定义,例如COORD_RE,即补丁是自包含的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | from itertools import product import types import openpyxl from openpyxl import worksheet from openpyxl.utils import range_boundaries def patch_worksheet(): """This monkeypatches Worksheet.merge_cells to remove cell deletion bug https://bitbucket.org/openpyxl/openpyxl/issues/365/styling-merged-cells-isnt-working Thank you to Sergey Pikhovkin for the fix """ def merge_cells(self, range_string=None, start_row=None, start_column=None, end_row=None, end_column=None): """ Set merge on a cell range. Range is a cell range (e.g. A1:E1) This is monkeypatched to remove cell deletion bug https://bitbucket.org/openpyxl/openpyxl/issues/365/styling-merged-cells-isnt-working """ if not range_string and not all((start_row, start_column, end_row, end_column)): msg ="You have to provide a value either for 'coordinate' or for\\ 'start_row', 'start_column', 'end_row' *and* 'end_column'" raise ValueError(msg) elif not range_string: range_string = '%s%s:%s%s' % (get_column_letter(start_column), start_row, get_column_letter(end_column), end_row) elif":" not in range_string: if COORD_RE.match(range_string): return # Single cell, do nothing raise ValueError("Range must be a cell range (e.g. A1:E1)") else: range_string = range_string.replace('$', '') if range_string not in self._merged_cells: self._merged_cells.append(range_string) # The following is removed by this monkeypatch: # min_col, min_row, max_col, max_row = range_boundaries(range_string) # rows = range(min_row, max_row+1) # cols = range(min_col, max_col+1) # cells = product(rows, cols) # all but the top-left cell are removed #for c in islice(cells, 1, None): #if c in self._cells: #del self._cells[c] # Apply monkey patch worksheet.Worksheet.merge_cells = merge_cells patch_worksheet() |
来源
https://bitbucket.org/openpyxl/openpyxl/issues/365/styling-merged-cells-isnt-working
我知道这很旧,但是我遇到了同样的问题,并且补丁对我不起作用,因此我找到了一种解决方法,方法是使用文档中的功能,该功能为合并的单元格添加了样式,然后循环所有合并单元格并在每个范围上调用函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | from openpyxl import load_workbook from openpyxl.styles import Border, Side, PatternFill, Font, GradientFill, Alignment def style_range(ws, cell_range, border=Border(), fill=None, font=None, alignment=None): """ Apply styles to a range of cells as if they were a single cell. :param ws: Excel worksheet instance :param range: An excel range to style (e.g. A1:F20) :param border: An openpyxl Border :param fill: An openpyxl PatternFill or GradientFill :param font: An openpyxl Font object """ top = Border(top=border.top) left = Border(left=border.left) right = Border(right=border.right) bottom = Border(bottom=border.bottom) first_cell = ws[cell_range.split(":")[0]] if alignment: ws.merge_cells(cell_range) first_cell.alignment = alignment rows = ws[cell_range] if font: first_cell.font = font for cell in rows[0]: cell.border = cell.border + top for cell in rows[-1]: cell.border = cell.border + bottom for row in rows: l = row[0] r = row[-1] l.border = l.border + left r.border = r.border + right if fill: for c in row: c.fill = fill file = 'file.xlsx' wb = load_workbook(file) ws = wb['Table 1'] thin = Side(border_style="thin", color="000000") border = Border(top=thin, left=thin, right=thin, bottom=thin) for range in ws.merged_cells.ranges: style_range(ws, str(range), border=border) wb.save('newExcel.xlsx') |
如果使用的是openpyxl 2.4,则micki_mouse提供的解决方案可能不起作用。我设法通过以下方式使其起作用:
1 2 3 4 5 6 7 8 9 10 11 | from openpyxl import load_workbook from openpyxl.utils import range_boundaries wb = load_workbook(template_path) ws = wb.active for merged_cells in ws.merged_cell_ranges: min_col, min_row, max_col, max_row = range_boundaries(merged_cells) style = ws.cell(row=min_row, column=min_col)._style for col in range(min_col, max_col + 1): for row in range(min_row, max_row + 1): ws.cell(row=row, column=col)._style = style |
基本上,您必须使用" merged_cell_ranges"(在2.5.0-b1中已弃用)才能正确访问工作表中的合并单元格。您还必须在单元构造函数中显式指定row和column
对我来说,这段代码可以正常工作:
1 2 3 4 5 6 7 | wb = load_workbook(template_path) ws = wb.active for merged_cells in ws.merged_cells.ranges: style = ws.cell(merged_cells.min_row, merged_cells.min_col)._style for col in range(merged_cells.min_col, merged_cells.max_col + 1): for row in range(merged_cells.min_row, merged_cells.max_row + 1): ws.cell(row, col)._style = style |
我只是找到所有合并的单元格,并将左上单元格的样式应用于其余单元格。
简单方法
转到文件夹C:\\\\ Python \\\\ Lib \\\\ site-packages \\\\ openpyxl \\\\ worksheet文件夹\\\\
打开worksheet.py文件
在merge_cells函数中,注释以下几行
1 2 3 4 5 6 7 8 9 10 | min_col, min_row, max_col, max_row = range_boundaries(range_string) rows = range(min_row, max_row+1) cols = range(min_col, max_col+1) cells = product(rows, cols) all but the top-left cell are removed for c in islice(cells, 1, None): if c in self._cells: del self._cells[c] |
保存。
仅此而已,对我有用。