Python Docx установить фон ячейки таблицы и цвет текста
Я использую Python 2.7 с DOCX, и я хотел бы изменить фон и цвет текста ячеек в моей таблице в зависимости от условий.
Я не смог найти ни одного полезного ресурса о форматировании одной ячейки
Какие-либо предложения?
Редактировать 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)
Все клетки все те же.
10 ответов
Если вы хотите покрасить конкретную ячейку в таблице, вы можете использовать код ниже. Например, допустим, вам нужно заполнить первую ячейку в первой строке таблицы цветом 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/
С помощью решения Никоса Тавулариса мы должны создать новый элемент для каждой ячейки. Я создал функцию, которая этого добивается. Работает в версии 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 = tc.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}
trPr.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(table.rows[row_ix].cell)
"""
5. Continue execution
"""
Похоже, вместо использования cell.text = "Something"
метод, который вам нужно использовать cell.add_paragraph("SomeText", a_style)
с определенным стилем - вероятно, один из:
- ColorfulGrid
- ColorfulGrid-Accent1
- ColorfulGrid-Accent2
- ColorfulGrid-Accent3
- ColorfulGrid-Accent4
- ColorfulGrid-Accent5
- ColorfulGrid-Accent6
Полный список здесь.
Если вы используете шаблон документа "по умолчанию" - в противном случае вам придется создать свой собственный.
Мы обнаружили, что если вы сделаете cell.add_paragraph('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
чтобы увидеть все стили, которые у вас есть. Вы можете определить новые стили, а также загрузить шаблонный документ уже с заранее определенными стилями.
Я сделал видео, демонстрирующее способ сделать это здесь. Я черпал вдохновение у людей выше, но у меня все еще были проблемы, поэтому я сделал это тоже, чтобы помочь другим.
https://www.youtube.com/watch?v=1Mgb95yigkk&amp;list=PL_W7lgC2xeJfWBUllp7ALKOM5GUBMCVoP
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")
Приведенный выше код изменит первую ячейку второй строки первой таблицы в документе. Пример вывода.
Взяв ответ Никоса Тавулариса, я бы просто изменил объявление shading_elm_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'))))
Если вы также хотите изменить цвет текста, вы можете установить его на прогонах внутри ячейки. Я написал эту функцию для одновременной обработки фона ячейки и цвета текста (используя метод 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)
Первоначально я пытался расширить решение Nikos, добавив
w:color="XXXXXX"
к
w:shd
тег, но это не сработало для меня. Однако настройка цвета шрифта при каждом запуске дала желаемый результат.
Я собрал предыдущие ответы и добавил некоторые функции. Не стесняйтесь тестировать: создайте новый файл, запустите «основную» часть внизу.
""" 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])
Если вы хотите перебирать ячейки подряд, используйте:
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)