Menu

Python error when setting the properties QGraphicsWidget::layout and QGraphicsWidget::effect

Help
2015-04-27
2015-05-04
  • Arnaud Barré

    Arnaud Barré - 2015-04-27

    Hi,

    First of all, thanks for this incredible project!

    In my project I need to set a layout in a QtGui::QGraphicsWidget object. Compared to a QWidget (and inherited) object, the 'layout' is set as a Qt property and should accept any object inheriting from the class QGraphicsLayout. Unfortunately when I try to assign a layout I have an error.

    from PythonQt import QtCore, QtGui
    gw = QtGui.QGraphicsWidget()
    gw.layout = QtGui.QGraphicsGridLayout()
    
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    AttributeError: Property 'layout' of type 'QGraphicsLayout*' does not accept an object of type        QGraphicsGridLayout (QGraphicsGridLayout (C++ object at: 0x10a94d900))
    

    You can use the associated setter 'QtGui.QGraphicsWidget::setLayout', but then the returned value for the property 'layout' is still None.

    from PythonQt import QtCore, QtGui
    gw = QtGui.QGraphicsWidget()
    print gw.layout # display None
    gw.setLayout(QtGui.QGraphicsGridLayout()) # Ok, but …
    print gw.layout # … still display None
    

    By digging a little, I also discovered that the property 'QtGui::QGraphicsObject::effect' has the same problem. However, this property has the associated getter 'QtGui::QGraphicsObject::graphicsEffect()' and I am able to retrieve the associated value.

    from PythonQt import QtCore, QtGui
    gw = QtGui.QGraphicsWidget()
    print gw.effect # display None
    gw.setEffect(QtGui.QGraphicsBlurEffect())
    print gw.graphicsEffect() # Display QGraphicsBlurEffect (QObject 0x109d408e0)
    print gw.effect # Display None
    

    At my level of comprehension, the problem is related to the fact the property 'layout' and 'effect' are associated with object/class which does not inherit from QObject. So they are not registered with the method 'PythonQtPrivate::registerClass()', but with the method 'PythonQtPrivate::registerCPPClass'. Then, these properties are seen by Python as pointer to C++ object.

    Is there any way to fix this problem?

    Thanks

    Arnaud

     
  • Florian Link

    Florian Link - 2015-04-28

    I did not yet have time to look into this, but it's on my todo list.
    I will post the results asap.

     
  • Florian Link

    Florian Link - 2015-05-04

    Your bug report is correct. There seem to be several issues with PythonQt handling of QProperties that store a pointer (I am not even sure if I think it is a good idea to use
    pointers in QProperties, but since it is the Qt API itself, we have to live with it).

    For the moment, the best fix I can offer is that you use:

    gw.setLayout(...)

    and then

    gw.layout_()

    to get the layout. Note that the _ causes PythonQt to prefer the slot instead of the property, but this has the side-effect that gw.layout will change to a slot after this call (you could consider this a PythonQt bug, but in this case it helps you workaround the problem).

    I will also look into fixing the QProperty handling of pointers, but I can't promise when I get time to work on this.

     
  • Florian Link

    Florian Link - 2015-05-04

    The problem is that Qt does not register the meta type for those properties, so their
    meta type id is invalid (-1).

    This can be fixed by calling the following in your init code:

    #include <QGraphicsLayout>
    #include <QGraphicsEffect>
    ...
    
    qRegisterMetaType<QGraphicsLayout*>("QGraphicsLayout*");
    qRegisterMetaType<QGraphicsEffect*>("QGraphicsEffect*");
    

    regards,
    Florian

     
  • Arnaud Barré

    Arnaud Barré - 2015-05-04

    Thanks for this patch, this gives me the possibility to get/set the properties QtGui.QGraphicsWidget::layout and 'QtGui.QGraphicsWidget::effect.

    However, I discovered than it is not possible to assign a layout (or an effect) if this one is created at the same time than it is assigned. This seems related to the life time of the object. For the 'layout' property, it even crashes Qt.

    For example, the next snippet attempts to assign a blur effect, but this one is deleted during its assignation (or seems so).

    from PythonQt import QtCore, QtGui
    gw = QtGui.QGraphicsWidget()
    gw.effect = QtGui.QGraphicsBlurEffect()
    print gw.effect # Display None
    

    However, if I create a temporary variable, this works as expected.

    from PythonQt import QtCore, QtGui
    gw = QtGui.QGraphicsWidget()
    gbe = QtGui.QGraphicsBlurEffect()
    gw.effect = gbe
    print gw.effect # Display QGraphicsBlurEffect (QObject 0x109d408e0)
    

    The worst case is when I do this test with the 'layout' property as it crashes Qt (certainly because the changed layout does not exist anymore).

    from PythonQt import QtCore, QtGui
    gw = QtGui.QGraphicsWidget()
    gw.layout = QtGui.QGraphicsGridLayout() # Crash in QGraphicsWidget::event (type QEvent::LayoutRequest)
    

    However, If I use a temporary variable, this works

    from PythonQt import QtCore, QtGui
    gw = QtGui.QGraphicsWidget()
    ggl = QtGui.QGraphicsGridLayout()
    gw.layout = ggl # it works!
    print gw.layout = QGraphicsGridLayout (C++ object at: 0x10b968b80)
    

    The reason why the assignation of 'layout' crashed, and not 'effect' might be due to the kind of object. QGraphicsEffect inherits from QObject and not QGraphicsLayout. The later is registered in PythonQt with 'PythonQtPrivate::registerCPPClass', while the former is registered with 'PythonQtPrivate::registerClass()'.

    In both case, the use of the setter (i.e. setLayout and setGraphicsEffect) does not help. For the 'effect' property the behaviour is the same, while for the 'layout' property, you have access to an object of the parent class.

    from PythonQt import QtCore, QtGui
    gw = QtGui.QGraphicsWidget()
    gw.setLayout(QtGui.QGraphicsGridLayout()) 
    # Seems to work but the stored object is now a QGraphicsLayout and not a QGraphicsGridLayout
    print gw.layout # QGraphicsLayout (C++ object at: 0x10ac33620)
    

    I do not know if this information might help you or not when you would like to implement the handling of a pointer into a QProperty, but at least this is a documented phenomena.

    Regards,

    Arnaud

     

Log in to post a comment.