1

I am in the process of creating, with PyQGIS, a PDF file.

First I set up the following objects:

  • A value project = QgsProject.instance()
  • A layoutManager object "manager"
  • A QgsPrintLayout object "layout"

Then I created a QgsLayoutItemTextTable object "table". Inside that table, I set up some columns and rows with custom values. I also set up a QgsLayoutFrame object "frame":

table.addFrame(frame)

Now I want to access one particular cell of the table and change the text color and font. How can I do that?

0

1 Answer 1

2

I do not see any straightforward way of modifying the style of an individual cell in a QgsLayoutItemTextTable. To be honest, I'm not sure that level of customisation is supported. There are methods such as setContentTextFormat() and setCellStyle(), but they are applied to either the entire table or a cellStyleGroup e.g. odd or even rows/columns, first or last row/column etc.

So this is not exactly answering your original question, but I would strongly recommend you to use a QgsLayoutItemManualTable instead.

As far as I can see, the main difference is that the table contents is composed of QgsTableCell objects which support full customisation such as background color, text format etc. at an individual cell level.

Here is a minimal example to create a manual table with some content and add it to a layout:

tbl_items = [['Item 1', 'Item 2', 'Item 3'],
            ['Item 4', 'Item 5', 'Item 6']]
            
tbl_contents = [[QgsTableCell(c) for c in r] for r in tbl_items]

l = QgsProject.instance().layoutManager().layoutByName('Test Layout')
t = QgsLayoutItemManualTable.create(l)
l.addMultiFrame(t)
t.setTableContents(tbl_contents)

# Base class for frame items, which form a layout multiframe item.
frame = QgsLayoutFrame(l, t)
frame.attemptResize(QgsLayoutSize(100, 25), True)
t.addFrame(frame)

l.refresh()

Then you can modify an individual cell format like so:

layout = QgsProject.instance().layoutManager().layoutByName('Test Layout')

frame = [f for f in layout.items() if isinstance(f, QgsLayoutFrame)][0]

# Access the table item
tbl = frame.multiFrame()

# Retrieve the table contents (nested lists)
tbl_contents = tbl.tableContents()

# Define the column & row indexes for your target cell
# *mind that the indexing starts from zero
col_idx = 1
row_idx = 1

# Retrieve the cell content
cell_content = tbl_contents[row_idx][col_idx].content()

# Create a new cell with the same content
new_cell = QgsTableCell(cell_content)

# Create a new text format object with font & color of your choice
txt_format = QgsTextFormat()
txt_format.setFont(QFont('Times'))
txt_format.setSize(12)
txt_format.setColor(QColor(0, 255, 0))

# Set text format to new cell
new_cell.setTextFormat(txt_format)

# Place the new cell in the table contents matrix
tbl_contents[row_idx][col_idx] = new_cell

# Set the modified contents to the table
tbl.setTableContents(tbl_contents)

# Refresh the layout
layout.refresh()

Before:

enter image description here

After:

enter image description here

4
  • Thank you for your answer. I am currently trying to implement it. Since my table is a QgsLayoutItemTextTable object, I got the error "AttributeError: 'QgsLayoutItemTextTable' object has no attribute 'tableContents'". But in QgsLayoutTable class, I found the method "getTableContents()". I believe it should do the same. However, I get the error "TypeError: getTableContents(self, contents: object): not enough arguments". It seems I am not calling it correctly. I wrote it that way : "tbl_contents = tbl.getTableContents()". Would you know the correct way to write this ? Commented Oct 18, 2023 at 10:10
  • @theonewhodidnotknow, I have updated my answer to suggest that you use a QgsLayoutItemManualTable instead with an example. P.s. getTableContents() does not do the same- it just fetches the contents, stores in a contents object and returns a boolean. You can call contents() on a QgsLayoutItemTextTable but it returns a matrix of plain strings, not QgsTableCells which can individually customised.
    – Ben W
    Commented Oct 19, 2023 at 8:28
  • 1
    Thank you for your answer, it works great. I changed it a little to fit my code and managed to customize my table even more, adding several new parameters (header, color, font, wolumn width, line height...). Indeed, it is easier to use a QgsLayoutItemManualTable table. Commented Oct 24, 2023 at 9:51
  • @theonewhodidnotknow, that's great. You're welcome.
    – Ben W
    Commented Oct 24, 2023 at 10:12

Not the answer you're looking for? Browse other questions tagged or ask your own question.