5

I'm trying to create, reposition and resize an HTML frame in a QGIS 3.2.0 Print Composer layout using PyQGIS:

proj = QgsProject.instance()
comp = QgsPrintLayout(proj)
blockStats = QgsLayoutItemHtml.create(comp)
blockStats.setFixedSize(QgsLayoutSize(34.3,25, QgsUnitTypes.LayoutMillimeters))
blockStats.attemptMove(QgsLayoutPoint(200,89, QgsUnitTypes.LayoutMillimeters))
blockStats.setFrameEnabled(True)
blockStats.setFrameStrokeWidth(QgsLayoutMeasurement(0.5,QgsUnitTypes.LayoutMillimeters))
comp.addLayoutItem(blockStats)

Lines 4 and 5 above give me "object has no attribute" errors for 'setFixedSize' and 'attemptMove' - how can I reposition and resize this object?


Using the answer by @ndawson I've revised my code as follows:

proj = QgsProject.instance()
comp = QgsPrintLayout(proj)
blockStatsHTML = QgsLayoutItemHtml.create(comp)
blockStatsHTML.setHtml("test<br><b>test</b>")
blockStatsHTML.loadHtml()
blockStatsFrame = QgsLayoutFrame(comp, blockStatsHTML)
blockStatsHTML.addFrame(blockStatsFrame)
blockStatsFrame.setFixedSize(QgsLayoutSize(34.3,25, QgsUnitTypes.LayoutMillimeters))
blockStatsFrame.attemptMove(QgsLayoutPoint(100,100, QgsUnitTypes.LayoutMillimeters))
blockStatsFrame.setFrameEnabled(True)
blockStatsFrame.setFrameStrokeWidth(QgsLayoutMeasurement(0.5, QgsUnitTypes.LayoutMillimeters))
comp.addLayoutItem(blockStatsFrame)
comp.moveItemToTop(blockStatsFrame)

I'm no longer getting Python errors, however the frame still isn't appearing in the print layout. I've tried changing the position, using positive and negative coordinates, but I can't make it show up.

Is there another step required to make it visible?


Just an update and clarification - I've added the following line at the end of the code:

lmgr.addLayout(comp)

When I open the layout in the print composer, the Items Panel contains only "Map 1" - there is no listing for the blockStatsFrame or blockStatsHTML item. So this tells me any other attempts at removing or resizing the item would be futile, since it doesn't exist in the layout as far as the print composer is concerned.

Apart from comp.addLayoutItem(blockStatsFrame), should anything else be necessary in order to add the item to the layout?


In case anyone is facing the same issue, the solution for me was in using attemptSetSceneRect to set the dimensions of the frame. Without this, the frame didn't appear in the layout at all. Note however that after using this method, setFixedSize doesn't appear to work. Relevant parts of my working code are below:

proj = QgsProject.instance()
lmgr = proj.layoutManager()
comp = QgsPrintLayout(proj)

# create block stats HTML multiframe
blockStatsHTML = QgsLayoutItemHtml.create(comp)

# create frame to show content from blockStatsHTML
blockStatsFrame = QgsLayoutFrame(comp, blockStatsHTML)
blockStatsFrame.attemptSetSceneRect(QRectF(10, 10, 30, 20))
blockStatsFrame.setFrameEnabled(True)
blockStatsHTML.addFrame(blockStatsFrame)

# set HTML contents
blockStatsHTML.setContentMode(QgsLayoutItemHtml.ManualHtml)
blockStatsHTML.setHtml("test<br><b>test</b>")
blockStatsHTML.loadHtml()

# reposition blockStatsFrame
blockStatsFrame.attemptMove(QgsLayoutPoint(10,10, QgsUnitTypes.LayoutMillimeters))

# set frame outline
blockStatsFrame.setFrameStrokeColor(QColor(255, 0, 255))
blockStatsFrame.setFrameStrokeWidth(QgsLayoutMeasurement(1, QgsUnitTypes.LayoutMillimeters))

# set frame background                        
blockStatsFrame.setBackgroundEnabled(True)
blockStatsFrame.setBackgroundColor(QColor(255, 255, 255))

# add frame to layout
comp.addLayoutItem(blockStatsFrame)

# add layout to layout manager
lmgr.addLayout(comp)
1
+50

Gareth, I gleaned a lot from Nyall's most-excellent test code over here Try something like this.

from PyQt5.QtCore import QRectF
... 
layout = lmgr.layoutByName("your_layout_name")
...
layout_html = QgsLayoutItemHtml(layout)
html_frame = QgsLayoutFrame(layout, layout_html)
html_frame.attemptSetSceneRect(QRectF(10, 10, 30, 20))
html_frame.setFrameEnabled(True)
layout_html.addFrame(html_frame)
layout_html.setContentMode(QgsLayoutItemHtml.ManualHtml)
layout_html.setHtml('test<br><b>test</b>')
layout_html.loadHtml()
html_frame.setFrameStrokeWidth(QgsLayoutMeasurement(0.5, QgsUnitTypes.LayoutMillimeters))
  • Fantastic. It works! The key appears to have been in the html_frame.attemptSetSceneRect(QRectF(10, 10, 30, 20)) line - without this, the frame doesn't show up at all. This has solved a huge problem for me - thanks a lot. Will update the code in my question to show the final solution. – Gareth Jones Sep 2 '18 at 22:03
3

HTML layout items are "multi frame" items, which means that their content is split over multiple QgsLayoutFrame items.

After creating your QgsLayoutItemHtml, you need to then create frames to display the content. E.g.:

blockStats = QgsLayoutItemHtml.create(comp)

# create a frame for showing content from blockStats
frame1 = QgsLayoutFrame(comp, blockStats)
blockStats.addFrame(frame1)

# and resize/move the frame
frame1.setFixedSize(QgsLayoutSize(34.3,25, QgsUnitTypes.LayoutMillimeters))
frame1.attemptMove(QgsLayoutPoint(200,89, QgsUnitTypes.LayoutMillimeters))
  • 1
    Brilliant - thanks Nyall, this has been really helpful. I'm not getting any errors now, but the frame isn't showing up on the print layout - maybe there's another step I'm missing. I'll edit the question to show my updated code. – Gareth Jones Aug 17 '18 at 1:57

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.