3

I have a PyQGIS script, which dynamically creates a print layout and opens it in the layout designer, when finished (example below). It works without problems when executed from the console. Now I want to integrate it into my scripts in the processing toolbox. Executed from the processing script, which was previously also running well, the same procedure causes problems and ultimately crashes QGIS. I have opened an issue on Github for this and have received the answer that this is not a QGIS error but that my script is not thread safe.

Does anybody know a way to accomplish my objective in processing scripts?

project = context.project()
manager = project.layoutManager()
layout = QgsPrintLayout(project)
layout.initializeDefaults()

layout.setName('Layout Name')

pages = layout.pageCollection()
pages.beginPageSizeChange()
page = pages.page(0)
page.setPageSize('A4')
pages.endPageSizeChange()
page_center = page.pageSize().width() / 2

title = QgsLayoutItemLabel(layout)
title.setText('Layout Title')
title.setFont(QFont('arial', 36))
title.adjustSizeToText()
title.setReferencePoint(1)
title.attemptMove(QgsLayoutPoint(page_center, 20))
layout.addItem(title)

map = QgsLayoutItemMap(layout)
map.setRect(20, 20, 20, 20)
ms = QgsMapSettings()
ms.setLayers([catchment])
rect = QgsRectangle(ms.fullExtent())
rect.scale(1.0)
ms.setExtent(rect)
map.setExtent(rect)
map.attemptResize(QgsLayoutSize(180, 90))
map.setReferencePoint(1)
map.attemptMove(QgsLayoutPoint(page_center, 50))
layout.addLayoutItem(map)

table = QgsLayoutItemTextTable(layout)
layout.addMultiFrame(table)
cols = [QgsLayoutTableColumn(), QgsLayoutTableColumn(), QgsLayoutTableColumn()]
cols[0].setHeading('Heading 0')
cols[1].setHeading('Heading 1')
table.setColumns(cols)
table.setContents([['Hello', 'world!']])
frame = QgsLayoutFrame(layout, table)
frame.attemptResize(QgsLayoutSize(30, 30), True)
frame.setReferencePoint(1)
frame.attemptMove(QgsLayoutPoint(page_center, 150))
table.addFrame(frame) # crash point 1

manager.addLayout(layout)

iface.openLayoutDesigner(layout) # crash point 2
5

The easiest way to do this would be to return the FlagNoThreading flag for your algorithm, and disable background processing.

  def flags(self):
      return super().flags() | QgsProcessingAlgorithm.FlagNoThreading
| improve this answer | |
  • Thank you so much! This solved 2 of my 3 problems: The map now renders and I can open the layout designer from script (previous crash point 2). One problem remains, though (crash point 2): The script runs fine but as soon as I want to open the result (automatically or manually through the layout manager) or just delete the resulting print layout, QGIS still crashes. Do you think, this also thread related or a sepparate issue? – lueho Jul 29 '19 at 9:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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