[QGIS-Developer] QGIS composer print layout
Giulio Fattori
giulio.fattori at tin.it
Fri Jan 22 05:48:52 PST 2021
Hello,
i'm developing a QGIS plugin algorithm that composes a print layout.
The attached code works but the map window appears in the composer with
the word "Rendering map".
and I get these messages:
WARNING QObject::connect: Cannot queue arguments of type 'QItemSelection'
(Make sure 'QItemSelection' is registered using
qRegisterMetaType().)
WARNING QObject::connect: Cannot queue arguments of type 'QItemSelection'
(Make sure 'QItemSelection' is registered using
qRegisterMetaType().)
WARNING QObject::connect: Cannot queue arguments of type 'QItemSelection'
(Make sure 'QItemSelection' is registered using
qRegisterMetaType().)
WARNING QObject::startTimer: Timers cannot be started from another thread
CRITICAL Qt : QObject::killTimer: Timers cannot be stopped from
another thread
CRITICAL Qt : QObject::startTimer: Timers cannot be started from
another thread
CRITICAL Qt : QObject::killTimer: Timers cannot be stopped from
another thread
CRITICAL Qt : QObject::startTimer: Timers can only be used with
threads started with QThread
Only after saving and reopening QGIS do I get the correct result in the
composer.
What is missing to make it work properly?
Can someone help me?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/qgis-developer/attachments/20210122/06d160ea/attachment.html>
-------------- next part --------------
# -*- coding: utf-8 -*-
"""
***************************************************************************
* Korto19 - last modified 17.01.2020/2021 19.01
* Put a map to composer
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
from PyQt5.QtGui import QFont
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsProject,
QgsPrintLayout,
QgsLayoutItemPage,
QgsLayoutItemMap,
QgsLayoutPoint,
QgsUnitTypes,
QgsLayoutSize,
QgsRectangle,
QgsLayoutItemLabel,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink)
from qgis import processing
from qgis.utils import iface
import math
class TestMapProcessingAlgorithm(QgsProcessingAlgorithm):
"""
"""
# Constants used to refer to parameters and outputs. They will be
# used when calling the algorithm from another algorithm, or when
# calling from the QGIS console.
INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
def tr(self, string):
"""
Returns a translatable string with the self.tr() function.
"""
return QCoreApplication.translate('Processing', string)
def createInstance(self):
return TestMapProcessingAlgorithm()
def name(self):
"""
Returns the algorithm name, used for identifying the algorithm. This
string should be fixed for the algorithm, and must not be localised.
The name should be unique within each provider. Names should contain
lowercase alphanumeric characters only and no spaces or other
formatting characters.
"""
return 'Test Map'
def displayName(self):
"""
Returns the translated algorithm name, which should be used for any
user-visible display of the algorithm name.
"""
return self.tr('Test Map')
def group(self):
"""
Returns the name of the group this algorithm belongs to. This string
should be localised.
"""
return self.tr('Test Map')
def groupId(self):
"""
Returns the unique ID of the group this algorithm belongs to. This
string should be fixed for the algorithm, and must not be localised.
The group id should be unique within each provider. Group id should
contain lowercase alphanumeric characters only and no spaces or other
formatting characters.
"""
return 'Test Map'
def shortHelpString(self):
"""
Returns a localised short helper string for the algorithm. This string
should provide a basic description about what the algorithm does and the
parameters and outputs associated with it..
"""
return self.tr("Test map composition")
def initAlgorithm(self, config=None):
"""
Here we define the inputs and output of the algorithm, along
with some other properties.
"""
# We add the input vector features source. It can have any kind of geometry.
self.addParameter(
QgsProcessingParameterFeatureSource(
self.INPUT,
self.tr('Input layer'),
[QgsProcessing.TypeVectorAnyGeometry]
)
)
def processAlgorithm(self, parameters, context, feedback):
"""
Here is where the processing itself takes place.
"""
source = self.parameterAsLayer(
parameters,
self.INPUT,
context
)
#Inizialize references
project = QgsProject.instance() #gets a reference to the project instance
manager = project.layoutManager() #gets a reference to the layout manager
root = project.layerTreeRoot() #get reference to tree root
#set pagesize, layout name and scale (fit or numeric)
pagesize = 'A3'
layoutName = "CompoMap_" + pagesize + ' ' + source.name()
map_scala = 'fit'
#If exist remove layout
layouts_list = manager.printLayouts()
for layout in layouts_list:
if layout.name() == layoutName:
manager.removeLayout(layout)
#create layout
layout = QgsPrintLayout(project)
layout.initializeDefaults()
layout.setName(layoutName)
layout.pageCollection().page(0).setPageSize(pagesize, QgsLayoutItemPage.Orientation.Portrait)
manager.addLayout(layout)
#calculates the size of the map minus the edges
xm = (layout.pageCollection().page(0).pageSize().width()-10)
ym = (layout.pageCollection().page(0).pageSize().height()-10)
#set layer active and fit map
iface.setActiveLayer(source)
root.findLayer(source.id()).setItemVisibilityChecked(True)
canvas = iface.mapCanvas()
canvas.setExtent(source.extent())
canvas.refresh()
#add map to layout and set position
map = QgsLayoutItemMap(layout)
map.setRect(20, 20, 20, 20)
map.setExtent(canvas.extent())
map.setId(source.name())
map.attemptMove(QgsLayoutPoint(5, 5, QgsUnitTypes.LayoutMillimeters))
map.attemptResize(QgsLayoutSize(xm, ym, QgsUnitTypes.LayoutMillimeters))
#override scale Test_map
if map_scala == 'fit':
h_map_scala = math.ceil(source.extent().height()/map.rect().height())*1000
w_map_scala = math.ceil(source.extent().width() /map.rect().width())*1000
map_scala = max(h_map_scala,w_map_scala)
extent = map.extent()
center = extent.center()
newwidth = extent.width() / map.scale() * map_scala
newheight = extent.height() / map.scale() * map_scala
x1 = center.x() - 0.5 * newwidth
y1 = center.y() - 0.5 * newheight
x2 = center.x() + 0.5 * newwidth
y2 = center.y() + 0.5 * newheight
map.setExtent(QgsRectangle(x1, y1, x2, y2))
#add map to layout
layout.addLayoutItem(map)
#select and lock map set
map.setLayers([source])
map.setKeepLayerSet(True)
map.setKeepLayerStyles(True)
map.setBackgroundEnabled(False)
#Add title
title = QgsLayoutItemLabel(layout)
title.setText(source.name())
title.setFont(QFont("Arial Black", 12))
title.adjustSizeToText()
title.attemptMove(QgsLayoutPoint(5, 5, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(title)
feedback.pushInfo("WOW The plugin is working as it should, created " + layoutName)
return {self.OUTPUT: None}
More information about the QGIS-Developer
mailing list