1

I am using python-docx to create a table with borders on all cells. When I merge cells involving outer cells some outer borders disappear. I use a function from other stackoverflow question -link shown as comment in code below- to set cell borders. How to fix that so outer borders are shown in merged cells?

Wrong borders:

Wrong borders

Good borders:

Good borders

Working example:

from docx import Document
from docx.oxml.shared import OxmlElement, qn


# from https://stackoverflow.com/questions/33069697/how-to-setup-cell-borders-with-python-docx
def set_cell_edges(cell, edges, color, style, width):
    """
     Parameter   Type                 Definition
     =========== ==================== ==========================================================================================
     cell        Cell                 Cell to apply edges
     edges       str, list, None      Cell edges, options are 'top', 'bottom', 'start' and 'end'
     color       str                  Edge color
     style       str                  Edge style, options are 'single', 'dotted', 'dashed', 'dashdotted' and 'double',
     width       int, float           Edge width in points
    """
    kwargs = dict()

    for edge in edges:
        kwargs[edge] = {'sz': width, 'val': style, 'color': color}

    tc = cell._tc
    tcPr = tc.get_or_add_tcPr()

    # check for tag existance, if none found then create one
    tcBorders = tcPr.first_child_found_in("w:tcBorders")
    if tcBorders is None:
        tcBorders = OxmlElement('w:tcBorders')
        tcPr.append(tcBorders)

    # list over all available tags
    for edge in ('start', 'top', 'end', 'bottom', 'insideH', 'insideV'):
        edge_data = kwargs.get(edge)
        if edge_data:
            tag = 'w:{}'.format(edge)

            # check for tag existance, if none found, then create one
            element = tcBorders.find(qn(tag))
            if element is None:
                element = OxmlElement(tag)
                tcBorders.append(element)

            # looks like order of attributes is important
            for key in ["sz", "val", "color", "space", "shadow"]:
                if key in edge_data:
                    element.set(qn('w:{}'.format(key)), str(edge_data[key]))


if __name__ == '__main__':

    rows = 3
    columns = 3

    document = Document()

    # create table
    table = document.add_table(rows=rows, cols=columns)

    # merge cells
    scell = table.rows[1].cells[1]
    ecell = table.rows[2].cells[2]
    scell.merge(ecell)

    # set 4 borders in all cells
    for row in table.rows:
        for cell in row.cells:
            set_cell_edges(cell, ['top', 'bottom', 'start', 'end'], '#ff0000', 'single', 1)

    document.save('test.docx')

Of course, I can set an extra column and row to set the specific borders. But it would be nice to fix it without that trick. Example with the trick.

Good borders with trick:

Good borders with tick

if __name__ == '__main__':

    rows = 3
    columns = 3

    document = Document()

    # create table
    table = document.add_table(rows=rows+1, cols=columns+1)

    # merge cells
    scell = table.rows[1].cells[1]
    ecell = table.rows[2].cells[2]
    scell.merge(ecell)

    # set 4 borders in all cells
    for row in table.rows[:-1]:
        for cell in row.cells[:-1]:
            set_cell_edges(cell, ['top', 'bottom', 'start', 'end'], '#ff0000', 'single', 1)

    # set top border in last row
    for cell in table.rows[-1].cells[:-1]:
        set_cell_edges(cell, ['top'], '#ff0000', 'single', 1)

    # set left border in last column
    for cell in table.columns[-1].cells[:-1]:
        set_cell_edges(cell, ['start'], '#ff0000', 'single', 1)

    document.save('test.docx')
girdeux
  • 585
  • 1
  • 5
  • 11

0 Answers0