使用openpyxl编辑Excel文件时丢失合并的单元格边框

时间:2016-08-03 03:48:07

标签: python excel openpyxl

我在Excel文件中有两张纸,第一张是封面纸,我不需要编辑。封面页中的合并单元格很少。但是,当我使用openpyxl编辑文件甚至没有触摸封面时,我会从合并的单元格中丢失边框。这个问题有什么问题吗?我正在使用Load_workbook('excel文件')来加载excel文件并使用不同的文件名保存它。

5 个答案:

答案 0 :(得分:3)

实际解决方案是通过在包含库之后包含此代码段来修补库代码,它可以解决问题。 (注意:不要担心缺少定义,例如COORD_RE,即补丁是自包含的)

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 :(得分:3)

我知道这很旧,但是我遇到了同样的问题,并且该补丁对我不起作用,因此我找到了一种解决方法,方法是使用文档中的函数,该函数为合并的单元格添加样式,然后循环遍历所有合并的单元格单元格并在每个范围内调用函数

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')

答案 2 :(得分:1)

对我来说,这段代码可以完美地工作:

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

我只是找到所有合并的单元格,然后将左上单元格的样式应用于其余单元格。

答案 3 :(得分:1)

如果您使用的是openpyxl 2.4,则micki_mouse提供的解决方案可能不起作用。我设法通过以下方式使其起作用:

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中弃用)才能正确访问工作表中的合并单元格。您还必须在单元格构造函数中明确指定行和列

答案 4 :(得分:0)

简单方法 1.转到文件夹C:\ Python \ Lib \ site-packages \ openpyxl \ worksheet文件夹\

  1. 打开worksheet.py文件

  2. 在merge_cells函数中,注释以下几行

    ''' 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]'''
    
  3. 保存。 仅此而已,对我有用。