[QGIS-Developer] QgsLayout.itemById returns wrong object

Enrico Ferreguti enricofer at gmail.com
Wed Jan 24 01:40:57 PST 2018


I'm testing the code under QGIS3, but I fear that
isinstance(item, item_class), in my case: isinstance(item,
QgsLayoutItemPicture)
returns always false because item is of QgsLayoutItem generic class

Nyall's workaround works for me without exceptions:

from qgis.core import QgsProject, QgsLayoutItemPicture
import sip
myLayout = QgsProject.instance().layoutManager().layoutByName('test')
myLayoutPicture =
sip.cast(myLayout.itemById("picture"),QgsLayoutItemPicture)
myLayoutPicture.setPicturePath("path to an image")


2018-01-24 10:20 GMT+01:00 Etienne Trimaille <etienne.trimaille at gmail.com>:

> Is-it possible to remove this function from SIP bindings? According to SIP
> version?
>
> It's a common issue, already raised on the mailing list and in plugin
> issue trackers.
>
> I'm copy/pasting another message/snippet from Martin which works perfectly:
>
> Not sure if that is related, was just looking into code of a plugin we
> use with QGIS 2.18 and there for getting composer items we have this
> helper method:
>
>     @staticmethod
>     def get_composition_item(comp, item_id, item_class):
>         for item in comp.items():
>             if isinstance(item, item_class):
>                 if item.id() == item_id:
>                     return item
>
> And you would call it e.g.:
> ver_label = self.get_composition_item(self.oview_compn, 'version',
> QgsComposerLabel)
>
> Not sure if that is to work around the same problem as you have - I
> didn't write that code. And to get composer map items, we use
> composition.getComposerMapById(id)
>
> 2018-01-24 10:09 GMT+03:00 Nyall Dawson <nyall.dawson at gmail.com>:
>
>> On 23 January 2018 at 22:34, Enrico Ferreguti <enricofer at gmail.com>
>> wrote:
>> > I'm trying to programmatically set a QgsLayoutPicture content in
>> QGIS3.0:
>> >
>> > 1) I create a new print composition and I name it 'test'
>> > 2) I create a picture frame in the composition and I call it 'picture'
>> > 3) I run the following code:
>> >
>> > from qgis.core import QgsProject
>> > myLayout = QgsProject.instance().layoutManager().layoutByName('test')
>> > myLayoutPicture = myLayout.itemById("picture")
>> > myLayoutPicture.setPicturePath("path to an image")
>> >
>> > and I get the following Exception:
>> > AttributeError: 'QgsLayoutItem' object has no attribute 'setPicturePath'
>> >
>> > If I inspect myLayoutPicture object I found it is a
>> qgis._core.QgsLayoutItem
>> > not a QgsLayoutPicture
>> >
>> > Is this a correct behaviour or is it an issue? How can I get the right
>> > Layout object?
>>
>> This became an issue after a certain sip version. It affects QGIS 2.x
>> also, and seems to be caused by sip being unable to automatically cast
>> classes which use multiple inheritance (like QgsComposerItem,
>> QgsLayoutItem). The consequence is that Python is only aware of the
>> base class, not the actual item subclass.
>>
>> I can't find anyway to fix this properly. So I hack around by forcing
>> sip to manually cast to the correct item type, e.g. by inserting two
>> lines* which look like this:
>>
>>         # screw you sip, I'll just manually cast
>>         real_item = sip.cast(item, QgsLayoutItemPicture)
>>
>> It's not pretty, but it works...
>>
>> Nyall
>>
>> * the first line is critical for the fix to work correctly
>> _______________________________________________
>> QGIS-Developer mailing list
>> QGIS-Developer at lists.osgeo.org
>> List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
>> Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/qgis-developer/attachments/20180124/bb5671de/attachment-0001.html>


More information about the QGIS-Developer mailing list