[PyQt] setapi and itemChange , setParentItem related bug.

Phil Thompson phil at riverbankcomputing.com
Mon Aug 13 16:02:03 BST 2012


On Sun, 12 Aug 2012 10:03:03 -0700 (PDT), Ryan Kim <ryan at moglue.com>
wrote:
> Hi. 
> 
> When I set  sip.setapi('QVariant', 2)  and reimplement itemChange
function
> of
> 
> QGraphicsItem, setParentItem doesn't work. 
> 
> I read this issue has been dealt with on this mailing list, but I guess
> It's
> still there.
> 
> Simple code to reproduce this behavior.
> ----------------------------------------------------------------------
> import sip
> sip.setapi('QVariant', 2)
> 
> from PyQt4 import QtCore
> from PyQt4 import QtGui
> import sys
> class TestItem(QtGui.QGraphicsRectItem):
>     def __init__(self,x,y,width,height,parent=None):
>         super(TestItem, self).__init__(x,y,width,height,parent)
>     def itemChange(self,change,value):
>         return super(TestItem,self).itemChange(change,value)
> if __name__ == '__main__':
>     app = QtGui.QApplication(sys.argv)
>     view = QtGui.QGraphicsView()
>     scene = QtGui.QGraphicsScene(0,0,1024,1024)
>     view.setScene(scene)
>     rect1 = TestItem(0,0,100,100)
>     rect2 = TestItem(100,100,50,50)
>     rect1.setFlag(QtGui.QGraphicsItem.ItemIsMovable,True)
>     rect2.setFlag(QtGui.QGraphicsItem.ItemIsMovable,True)
>     rect2.setParentItem(rect1)
>     scene.addItem(rect1)
>     scene.addItem(rect2)
>     view.show()
>     sys.exit(app.exec_())
> ----------------------------------------------------------------------
> Big rectangle is parent of small rectangle.
> 
> But If you move big rectangle, child doesn't move along with it's
parent.
> 
> if u comment out sip.setapi('QVariant', 2), it just works. 
> 
> Appreciate any kind of help.

The problem is that this invokes a conversion from TestItem to QVariant.
In order to preserve all the attributes of TestItem PyQt wraps it with an
internal C++ class that Qt knows nothing about which results in the
reparenting process failing. One solution might be to automatically treat
the TestItem as a QGraphicsItem (which Qt does know about) but that would
cause another set of problems.

In the absence of a general solution (I can't think of one) the workaround
is to use sip.cast()...

    def itemChange(self, change, value):
        result = super(TestItem, self).itemChange(change, value)

        if isinstance(result, QtGui.QGraphicsItem):
            result = sip.cast(result, QtGui.QGraphicsItem)

        return result

Phil


More information about the PyQt mailing list