PyQGIS Print Layouts – Managing Print Layouts Using PyQGIS in QGIS 3

pyqgispyqgis-3qgisqgis-3

I'm struggling to understand how to manage print layouts using python for QGIS. For example, I am starting with Zero exisiting print layouts in my layout manager. I create a new print layout and add a label to it with this code:

project = QgsProject.instance()                                  
manager = project.layoutManager()
layout = QgsPrintLayout(project)
layout.initializeDefaults()                         
layoutName = "PrintLayout"
layout.setName(layoutName)
manager.addLayout(layout)  

layout.setName(layoutName)
manager.addLayout(layout)

title = QgsLayoutItemLabel(layout)
title.setText("Title Here")
title.setFont(QFont("Arial", 28))
title.adjustSizeToText()
layout.addLayoutItem(title)
title.attemptMove(QgsLayoutPoint(10, 4, QgsUnitTypes.LayoutMillimeters))

This is simple enough, it creates a new print layout called "PrintLayout" and it looks like this:
enter image description here

But if I run this code another time, I start getting problems. If I run exactly the same code, except I change the following line:

title.setText("Title There")

I get the following result. As you can see, "Title There" and "Title Here" are now overlaid on top of each other. This isn't good.
enter image description here

So I started thinking if an existing print layout exists with the same name, maybe I can delete that layout and create a new one. So I try the following code:

project = QgsProject.instance()                                  
manager = project.layoutManager()
layout = QgsPrintLayout(project)
layout.initializeDefaults()                         
layoutName = "PrintLayout"
layout.setName(layoutName)
manager.addLayout(layout)  

layouts_list = manager.printLayouts()

for layout in layouts_list:
    print(layout.name())

for layout in layouts_list:
    if layout.name() == layoutName:
        layouts_list.remove(layout)

for layout in layouts_list:
    print(layout.name())

title = QgsLayoutItemLabel(layout)
title.setText("Title There")
title.setFont(QFont("Arial", 28))
title.adjustSizeToText()
layout.addLayoutItem(title)
title.attemptMove(QgsLayoutPoint(10, 4, QgsUnitTypes.LayoutMillimeters))

Notice, I created a variable "layouts_list" which stores my layouts and for loop to check the names of existing layouts, if the name equals the new layout I want to create, I remove before creating a new one. Also, I print the layout names from the layout manager before and after checking the layout names.

However, it seems the .remove() method doesn't actually remove a layout from the layout manager.

J.Monticolo suggested I try the .removeLayout() method. So I modified my for loop like this:

for layout in layouts_list:
    if layout.name() == layoutName:
        manager.removeLayout(layout)

This does actually remove the layout from the layout manager. But I'm met with this error:
enter image description here

This makes sense. I did delete the layout. But a new layout is not created. They should be as my remaining code makes a new layout and adds a title to it.

Why does this error message stop the code, before creating a new layout?

Here is the final code all together:

project = QgsProject.instance()                                  
manager = project.layoutManager()
layout = QgsPrintLayout(project)
layout.initializeDefaults()                         
layoutName = "PrintLayout"
layout.setName(layoutName)
manager.addLayout(layout)  

layouts_list = manager.printLayouts()

for layout in layouts_list:
    if layout.name() == layoutName:
        manager.removeLayout(layout)

layout.setName(layoutName)
manager.addLayout(layout)

title = QgsLayoutItemLabel(layout)
title.setText("Title There")
title.setFont(QFont("Arial", 28))
title.adjustSizeToText()
layout.addLayoutItem(title)
title.attemptMove(QgsLayoutPoint(10, 4, QgsUnitTypes.LayoutMillimeters))

Best Answer

You attempt to set a name to a deleted object.

You need to create a new object :

[...]
for layout in layouts_list:
    if layout.name() == layoutName:
        manager.removeLayout(layout)

layout = QgsPrintLayout(project)
layout.setName(layoutName)
[...]
Related Question