3

I am creating a script to export an attribute table in pdf format with PyQGIS 3. The number of features is different regarding the farmer's number of fields and features are sorted by the field id.

Regarding the number of fields, the attribute table may need to be extended to next page(s). I would like to repeat the main informations about the farm on the next page(s). Like a header only starting from the second page.

I first defined as many QgsLayoutItemLabel as there were page (making if statements regarding the number of features) but it makes my script really heavy.

There is no map in the layout so I would like to know if it's possible to do it without using the atlas composer.

The following script allows to put my header on the 2nd page, and I would like to repeat it on the 3rd page without creating a new QgsLayoutItemLabel.

project = QgsProject.instance()
layout = QgsPrintLayout(project)

BD = project.mapLayersByName('Base de données client')[0]
prop_field = BD.fields().indexFromName('Propriétaire')
prop = BD.getFeature(idCode).attribute(prop_field)

header1 = QgsLayoutItemLabel(layout)
header1.setText("Liste des contraintes - " + prop)
header1.setFont(QFont("Ms Shell Dlg 2", 11))
header1.setHAlign(Qt.AlignLeft)
header1.setMinimumSize(QgsLayoutSize(133.376, 8.215, QgsUnitTypes.LayoutMillimeters))
header1.attemptMove(QgsLayoutPoint(6, 3.590),page=1)

EDIT

I tried the following code that allows to duplicate an item, but I don't understand why both items are at the same location, on the 1st page, even if a different page is called:

# Crédit
def generateLayoutItemCredit(layoutn, pagenb):
    credit_text = QgsLayoutItemLabel(layoutn)
    credit_text.setText("Plan réalisé par le Club agroenvironnemental de l'Estrie")
    credit_text.setFont(QFont("Ms Shell Dlg 2", 11))
    credit_text.setHAlign(Qt.AlignLeft)
    credit_text.setMarginX(3)
    credit_text.setMinimumSize(QgsLayoutSize(130, 8, QgsUnitTypes.LayoutMillimeters))
    credit_text.attemptMove(QgsLayoutPoint(6, 268),page=pagenb)
    layoutn.addLayoutItem(credit_text) #add layout item inside the function
    return credit_text

generateLayoutItemCredit(layout, 1)
generateLayoutItemCredit(layout, 2)

EDIT 2 Following the same logic as the answer provided, here is how a) I repeated a label only from the 2nd page and b) I repeated a label with the text changing for each page

a) Header repeated from the 2nd page

def generateLayoutItemHeader(layoutn, pagenb):
    header_text = QgsLayoutItemLabel(layoutn)
    header_text.setText("Liste des contraintes - " + prop)
    header_text.setFont(QFont("Ms Shell Dlg 2", 11))
    header_text.setHAlign(Qt.AlignLeft)
    header_text.setMinimumSize(QgsLayoutSize(120, 8, QgsUnitTypes.LayoutMillimeters))
    header_text.attemptMove(QgsLayoutPoint(9, 3),page=pagenb)
    return header_text

# additionnal number of pages
pages_sup=4
for i in range(0, pages_sup):
    page = QgsLayoutItemPage(layout)
    page.setPageSize('Letter', QgsLayoutItemPage.Portrait)
    layout.pageCollection().addPage(page)

for i in range(1, pages_sup + 1):
    header = generateLayoutItemHeader(layout, i)
    layout.addLayoutItem(header)

b) Updating the page number

def generateLayoutItemPage(layoutn, pagenb, label):
    page_text = QgsLayoutItemLabel(layout)
    page_text.setFont(QFont("Ms Shell Dlg 2", 10))
    page_text.attemptMove(QgsLayoutPoint(193, 3.590),page=pagenb)
    page_text.setHAlign(Qt.AlignRight)
    page_text.setMinimumSize(QgsLayoutSize(15, 8.215, QgsUnitTypes.LayoutMillimeters))
    page_text.setText(label)
    return page_text

currPage = 1    
for j in range(1, pages_sup + 1):
    labelp = 'page' + str(currPage) + '/' + str(pages_sup + 1)
    pagel = generateLayoutItemPage(layout, j-1, labelp)
    currPage+=1
    layout.addLayoutItem(pagel)
2

1 Answer 1

2

You need to add pages before attempting to move your items. Your current code tries to move items to "non existing pages". A demo below (I start from an existing empty layout named demo_multi with one page)

project = QgsProject.instance()
projectLayoutManager = project.layoutManager()
layout = projectLayoutManager.layoutByName('demo_multi')

def generateLayoutItemCredit(layoutn, pagenb):
    credit_text = QgsLayoutItemLabel(layoutn)
    credit_text.setText("Plan réalisé par le Club agroenvironnemental de l'Estrie")
    credit_text.setFont(QFont("Ms Shell Dlg 2", 11))
    credit_text.setHAlign(Qt.AlignLeft)
    credit_text.setMarginX(3)
    credit_text.setMinimumSize(QgsLayoutSize(130, 8, QgsUnitTypes.LayoutMillimeters))
    credit_text.attemptMove(QgsLayoutPoint(6, 268),page=pagenb)
    return credit_text

# additionnal number of pages
pages_sup=2
# Loop twice to add 2 pages
for i in range(0, pages_sup):
    page = QgsLayoutItemPage(layout)
    page.setPageSize('A4', QgsLayoutItemPage.Portrait)
    layout.pageCollection().addPage(page)

# Add items to page by looping 3 times
for i in range(0, pages_sup + 1): # Loop from 0 to 2
    credit = generateLayoutItemCredit(layout, i + 1) # Fix page number to i by adding 1
    layout.addLayoutItem(credit)
1
  • 1
    Thank you once again for your help ThomasG77 ! Commented Mar 2, 2021 at 2:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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