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