Re: [QGIS-Developer] QgsLayout.itemById returns wrong object
On Tue, 23 Jan 2018 at 22:34, Enrico Ferreguti 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? Coming back to this older discussion -- last week a workaround was pushed to 3.3 master to try and avoid this issue. I'd love for widespread testing of the currently nightlies to confirm that the issue is now fixed (or not)! If anyone is still hitting this issue, please report here the build number and what method you are calling to retrieve a layout item. Fingers crossed :) would be great to have this solved for 3.4! Nyall > > Regards. > Enrico Ferreguti > ___ > QGIS-Developer mailing list > QGIS-Developer@lists.osgeo.org > List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer > Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer ___ QGIS-Developer mailing list QGIS-Developer@lists.osgeo.org List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Re: [QGIS-Developer] QgsLayout.itemById returns wrong object
On 24 January 2018 at 19:20, Etienne Trimaillewrote: > Is-it possible to remove this function from SIP bindings? According to SIP > version? > Unfortunately I don't think this would help - we'd have to remove every method which returns a QgsLayoutItem to do so - and there's some things in API which are only possible with these methods. It's also proven to be an issue even in the most recent Qt and SIP versions, so we'd have to just remove these methods from the bindings full stop. There's also underlying Qt base classes which returns these items which we can't control (eg QGraphicsScene::items() ). > It's a common issue, already raised on the mailing list and in plugin issue > trackers. I think the real solution is to get it fixed upstream. > 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) I don't see how this helps though - unless some magic in the isinstance call forces sip to correctly cast the item type? Martin? > 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) That's gone in 3.0 ;) Map ids where old and crufty, and now everything is done with the uuids. But unfortunately the methods for retrieving items by uuid all return a QgsLayoutItem pointer, so will suffer the same sip casting bug. It's bad all round. That's why I think we need to try as hard as possible to get this resolved upstream so we can do away with all the hacks. Nyall ___ QGIS-Developer mailing list QGIS-Developer@lists.osgeo.org List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Re: [QGIS-Developer] QgsLayout.itemById returns wrong object
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: > 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 : > >> On 23 January 2018 at 22:34, Enrico Ferreguti >> 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@lists.osgeo.org >> List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer >> Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer >> > > ___ QGIS-Developer mailing list QGIS-Developer@lists.osgeo.org List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Re: [QGIS-Developer] QgsLayout.itemById returns wrong object
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: > On 23 January 2018 at 22:34, Enrico Ferreguti 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@lists.osgeo.org > List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer > Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer > ___ QGIS-Developer mailing list QGIS-Developer@lists.osgeo.org List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Re: [QGIS-Developer] QgsLayout.itemById returns wrong object
On 23 January 2018 at 22:34, Enrico Ferregutiwrote: > 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@lists.osgeo.org List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Re: [QGIS-Developer] QgsLayout.itemById returns wrong object
2018-01-23 14:34 GMT+02:00 Enrico Ferreguti: > 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' Which QGIS revision do you use? I can not reproduce your issue on master, all works as expected. -- Alexander Bruy ___ QGIS-Developer mailing list QGIS-Developer@lists.osgeo.org List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Re: [QGIS-Developer] QgsLayout.itemById returns wrong object
On Tue, Jan 23, 2018 at 1:34 PM, Enrico Ferregutiwrote: > 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? > Yes, it is the correct behavior, the method returns a pointer to the base class which is QgsLayoutItem. In the C++ API there is a template method to retrieve all objects of a certain type but it's not exposed to Python (that's not even possible with current SIP I think): template void layoutItems( QList ) const SIP_SKIP Sorry but I don't have an answer to your last question. -- Alessandro Pasotti w3: www.itopen.it ___ QGIS-Developer mailing list QGIS-Developer@lists.osgeo.org List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
[QGIS-Developer] QgsLayout.itemById returns wrong object
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? Regards. Enrico Ferreguti ___ QGIS-Developer mailing list QGIS-Developer@lists.osgeo.org List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer