[QGIS-Developer] QGIS composer print layout
Giulio Fattori
giulio.fattori at tin.it
Sun Jan 24 04:17:22 PST 2021
Il 23/01/2021 15:35, JD L ha scritto:
> Hi Giulio,
>
> add the flags methods to tell your algorithm is not thread-safe. From
> the documentation :
> https://docs.qgis.org/3.16/en/docs/user_manual/processing/scripts.html#flags
> <https://docs.qgis.org/3.16/en/docs/user_manual/processing/scripts.html#flags>
>
> If your algorithm is regularly crashing, you are probably using API
> calls which are not safe to do in a background thread. Try returning
> the *QgsProcessingAlgorithm.FlagNoThreading flag from your algorithm’s
> flags() method* to force Processing to run your algorithm in the main
> thread instead.
>
> I just tested and it works.
>
> Regards,
>
> Le ven. 22 janv. 2021 à 14:56, Giulio Fattori <giulio.fattori at tin.it
> <mailto:giulio.fattori at tin.it>> a écrit :
>
> 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?
>
> _______________________________________________
> QGIS-Developer mailing list
> QGIS-Developer at lists.osgeo.org <mailto:QGIS-Developer at lists.osgeo.org>
> List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
> <https://lists.osgeo.org/mailman/listinfo/qgis-developer>
> Unsubscribe:
> https://lists.osgeo.org/mailman/listinfo/qgis-developer
> <https://lists.osgeo.org/mailman/listinfo/qgis-developer>
>
Hi Daniel,
thanks for your kind response, could you send me the code correct as you
say?
Regards
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/qgis-developer/attachments/20210124/7571e529/attachment-0001.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