python-docx设置表格单元格的背景和文本颜色



我在docx中使用python 2.7,我想根据条件更改表中单元格的背景和文本颜色。

我找不到任何关于单单元格格式化的有用资源

有什么建议吗?

编辑1

我的代码

style_footer = "DarkList"
style_red = "ColorfulList"
style_yellow = "LightShading"
style_green = "MediumShading2-Accent6"
style_transperent = "TableNormal"
for a,rec in enumerate(data):
    #V headinh se piše prvo polje iz table heada
    document.add_heading(rec['tableHead'][0][0], level=1)
    image_path = imageFolder + "\" + slike[a]
    document.add_picture(image_path, height=Inches(3.5))
    #y += 28
    #worksheet.insert_image( y, 1,imageFolder + "/" + slike[a])

    for i, head in enumerate(rec['tableHead']):
        table = document.add_table(rows=1, cols = len(head))
        hdr_cells = table.rows[0].cells
        for a in range(0,len(head)):
            hdr_cells[a].text = head[a] 

    for a,body in enumerate(rec['tableData']):
        row_cells = table.add_row().cells
        for a in range(0,len(body)):
            if body[a]['style'] == 'footer':
                stil = style_footer
            elif body[a]['style'] == 'red':
                stil = style_red
            elif body[a]['style'] == 'yellow':
                stil = style_yellow
            elif body[a]['style'] == 'green':
                stil = style_green
            else:
                stil = style_transperent
            row_cells[a].add_paragraph(body[a]['value'], stil)
document.save(wordDoc)

所有单元格仍然相同。

如果您想用颜色填充表中的特定单元格,可以使用下面的代码。例如,假设您需要用RGB颜色1F5C8B:填充表第一行的第一个单元格

from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
shading_elm_1 = parse_xml(r'<w:shd {} w:fill="1F5C8B"/>'.format(nsdecls('w')))
table.rows[0].cells[0]._tc.get_or_add_tcPr().append(shading_elm_1)

现在,如果您还想用相同的颜色填充第一行中的第二个单元格,则应该创建一个新元素否则,如果使用与上面相同的元素,填充将继续移动,并从第一个单元格中消失。。。

shading_elm_2 = parse_xml(r'<w:shd {} w:fill="1F5C8B"/>'.format(nsdecls('w')))
table.rows[0].cells[1]._tc.get_or_add_tcPr().append(shading_elm_2)

对于其他细胞以此类推。

来源:https://groups.google.com/forum/#!topic/python docx/-c3OrRHA3qo

使用Nikos-Tavoularis的解决方案,我们必须为每个单元创建一个新元素。我创建了一个功能来实现这一点。适用于Python 3.5.6版和Python docx 0.8.10版

from docx.oxml import OxmlElement
from docx.oxml.ns import qn
def set_table_header_bg_color(table.rows[row_ix].cell):
    """
    set background shading for Header Rows
    """
    tblCell = cell._tc
    tblCellProperties = tblCell.get_or_add_tcPr()
    clShading = OxmlElement('w:shd')
    clShading.set(qn('w:fill'), "00519E") #Hex of Dark Blue Shade {R:0x00, G:0x51, B:0x9E}
    tblCellProperties.append(clShading)
    return cell
"""
End of set_table_header_bg_color Function
"""
# main function
"""
..
..
..
1. Load Document
..
2. Access the required section
..
3. Load the required Table
..
4. Traverse to the cell by accessing the rows object
..
"""
for each_row in table.rows :
    for each_cell in each_row.cells:
        if each_cell.value satisfies a condition:
            set_table_header_bg_color(each_cell)
"""
5. Continue execution
"""

我们发现,如果你使用cell.add_paraggraph('sometext',style_object),它会保留现有的空段落,并添加一个带有样式的附加段落,这并不理想。

你想做的是:

# replace the entire content of cell with new text paragraph
cell.text = 'some text'
# assign new style to the first paragraph
cell.paragraphs[0].style = style_object 

注意,样式应用于段落而不是单元格,这对于背景色来说并不理想(因为如果你有一些填充,它不会填充输入单元格。我还没有找到解决这个问题的方法(除非你希望每个单元格都有背景色,你可以将样式应用于table.style)。

此外,请确保您的样式已定义。你可以查看

styles = documents.styles
for s in styles:
  print s.name

看看你所有的风格。您可以定义新样式,也可以加载已具有预定义样式的模板文档。

看起来您不需要使用cell.text = "Something"方法,而是需要使用具有定义样式的cell.add_paragraph("SomeText", a_style)——可能是以下样式之一:

  • ColorfulGrid
  • ColorfulGrid-Accent1
  • ColorfulGrid-Accent2
  • ColorfulGrid-Accent3
  • ColorfulGrid-Accent4
  • ColorfulGrid-Accent5
  • ColorfulGrid-Accent6

此处列出完整列表

如果您使用"默认"模板文档,那么您将不得不创建自己的模板文档。

根据Nikos Tavouraris的回答,我只需要更改shading_el_1声明,就好像你在循环中包含了单元格颜色一样——例如,事情可能会变得一团糟。

因此,我的建议是:

from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
table.rows[0].cells[0]._tc.get_or_add_tcPr().append(parse_xml(r'<w:shd {} w:fill="1F5C8B"/>'.format(nsdecls('w'))))

我制作了一个视频,演示了一种方法。我从上面的人那里获得了灵感,但我仍然有问题,所以我也让它帮助了其他人。

https://www.youtube.com/watch?v=1Mgb95yigkk&list=PL_W7lgC2xeJfWBUllp7ALKOM5UBMCVoP

    from docx import Document
    from docx.oxml import OxmlElement
    from docx.oxml.ns import qn
    document = Document("youfile.docx")
    Table = document.tables[0]
    #GET CELLS XML ELEMENT
    cell_xml_element = Table.rows[1].cells[0]._tc
    #RETRIEVE THE TABLE CELL PROPERTIES
    table_cell_properties = cell_xml_element.get_or_add_tcPr()
    #CREATE SHADING OBJECT
    shade_obj = OxmlElement('w:shd')
    #SET THE SHADING OBJECT
    shade_obj.set(qn('w:fill'), "ff00ff")
    #APPEND THE PROPERTIES TO THE TABLE CELL PROPERTIES
    table_cell_properties.append(shade_obj)
    document.save("yoursavefile.docx")

上面的代码将更改文档中第一个表第二行的第一个大提琴。输出示例。

如果您想循环通过一行中的单元格,请使用:

def color_row(row=0):
    'make row of cells background colored, defaults to column header row'
    row = t.rows[row]
    for cell in row.cells:
        shading_elm_2 = parse_xml(r'<w:shd {} w:fill="1F5C8B"/>'.format(nsdecls('w')))
        cell._tc.get_or_add_tcPr().append(shading_elm_2)

运行函数以对第二行中的单元格进行着色

color_row(2)

如果您也想更改文本颜色,您可以在单元格内的运行中设置它。我写这个函数是为了同时处理单元格背景和文本颜色(使用Nikos的填充方法):

def shade_cell(cell, fill=None, color=None):
    if fill:
        shading_elm = parse_xml(r'<w:shd {} w:fill="{}"/>'.format(nsdecls('w'), fill))
        cell._tc.get_or_add_tcPr().append(shading_elm)
    if color:
        for p in cell.paragraphs:
            for r in p.runs:
                r.font.color.rgb = RGBColor.from_string(color)

我最初试图通过在w:shd标签中添加w:color="XXXXXX"来扩展Nikos的解决方案,但这对我来说不起作用。然而,每次运行时设置字体颜色都得到了我想要的结果。

我已经编译了前面的答案并添加了一些功能。请随意测试:创建新文件运行"主";底部的部分。

""" adder for python-docx in order to change text style in tables:
font color, italic, bold
cell background color
based on answers on
https://stackoverflow.com/questions/26752856/python-docx-set-table-cell-background-and-text-color
"""
import docx # import python-docx (in order to create .docx report file)
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
def change_table_cell(cell, background_color=None, font_color=None, font_size=None, bold=None, italic=None):
    """ changes the background_color or font_color or font style (bold, italic) of this cell.
    Leave the params as 'None' if you do not want to change them.
    params:
        cell: the cell to manipulate
        background_color: name for the color, e.g. "red" or "ff0000"
        font_color:
        font_size: size in pt (e.g. 10)
        bold:   requested font style. True or False, or None if it shall remain unchanged
        italic: requested font style. True or False, or None if it shall remain unchanged
    background_color: the color of cells background"""
    if background_color:
        shading_elm = parse_xml(r'<w:shd {} w:fill="{}"/>'.format(nsdecls('w'), background_color))
        cell._tc.get_or_add_tcPr().append(shading_elm)
    if font_color:
        for p in cell.paragraphs:
            for r in p.runs:
                r.font.color.rgb = docx.shared.RGBColor.from_string(font_color)
    if font_size:
        for p in cell.paragraphs:
            for r in p.runs:
                r.font.size = docx.shared.Pt(font_size)
    if bold is not None:
        for p in cell.paragraphs:
            for r in p.runs:
                r.bold = bold
    if italic is not None:
        for p in cell.paragraphs:
            for r in p.runs:
                r.italic = italic
def change_table_row(table_row, background_color=None, font_color=None, font_size=None, bold=None, italic=None):
    for cell in table_row.cells:
        change_table_cell(cell, background_color=background_color, font_color=font_color, font_size=font_size,
                          bold=bold,
                          italic=italic)
if __name__ == "__main__":  # do the following  code only if we run the file itself
    #document = docx.Document('template.docx') # create an instance of a word document, use the style that we have defined in 'template.docx'
    document = docx.Document()
    num_rows = 4
    num_cols = 3
    table = document.add_table(rows=num_rows, cols=num_cols)  # create empty table
    #table.style = document.styles['MyTableStyleBlue']  # test overwriting the predefined style
    # fill table
    for row in range(num_rows):
        for col in range(num_cols):
            table.rows[row].cells[col].text = f'row/col=({row},{col})'
    """ change color (see https://stackoverflow.com/questions/26752856/python-docx-set-table-cell-background-and-text-color) """
    # Nikos Tavoularis answered Apr 18, 2017 at 8:38
    shading_elm_1 = parse_xml(r'<w:shd {} w:fill="1F5C8B"/>'.format(nsdecls('w')))
    table.rows[0].cells[0]._tc.get_or_add_tcPr().append(shading_elm_1)
    # test new function derived from dyoung's answere of May 25 at 7:34, 2022
    change_table_cell(table.rows[0].cells[0], background_color=None, font_color="ff0000", bold=False)
    change_table_cell(table.rows[1].cells[2], background_color="00ff00", font_color="ff0000", font_size=20, bold=True)
    change_table_row(table.rows[3], background_color="lightgreen", font_color="0000ff", italic=True)  # https://www.delftstack.com/howto/python/colors-in-python/
    document.save('table_shading_test.docx')

如果您想更改整列的背景,这里有一个函数。将行数和表列数作为参数传递给此函数。循环浏览行数并更改每个单元格的背景色。

# to change background colour of the column cells
def change_columns_background(row_count, *columns):
    for i in range(1, row_count + 1):
        shading_elm_1 = parse_xml(
            r'<w:shd {} w:fill="BDD6EE"/>'.format(nsdecls('w')))
        columns[0].cells[i]._tc.get_or_add_tcPr().append(shading_elm_1)

示例函数调用:

# change the background color of first column for a table
        change_columns_background(row_count, my_table.columns[0])

相关内容

  • 没有找到相关文章

最新更新