<div dir="ltr">We need to reparent a graphics item to another. My colleague came across the weirdest bug: just decorating a function with pyqtSlot(QPushButton) causes QGraphicsItem.itemChange() to fail reparenting (reparentItem()). Just run the following example with stock PyQt 5.5.1 (downloaded from riverbank website in binary form) and observe the output: <div><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div>import sys</div></div><div><div>from PyQt5.QtCore import pyqtSlot, QVariant, QObject</div></div><div><div>from PyQt5.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QPushButton, QGraphicsItem, QGraphicsRectItem</div></div><div><div><br></div></div><div><div><br></div></div><div><div># no decorator:              Good</div></div><div><div># @pyqtSlot(QObject)       # Good</div></div><div><div># @pyqtSlot(QWidget)       # Good</div></div><div><div># @pyqtSlot(list)          # Good</div></div><div><div># @pyqtSlot(int)           # Good</div></div><div><div># @pyqtSlot(QGraphicsItem) # reparenting BROKEN!!!</div></div><div><div>@pyqtSlot(QPushButton)     # reparenting BROKEN!!!</div></div><div><div>def callback(button: QPushButton):</div></div><div><div>    pass</div></div><div><div><br></div></div><div><div><br></div></div><div><div>class Test(QGraphicsRectItem):</div></div><div><div>    def __init__(self, parent):</div></div><div><div>        super().__init__(parent)</div></div><div><div><br></div></div><div><div>    def itemChange(self, change: QGraphicsItem.GraphicsItemChange, new_value: QVariant) -> QVariant:</div></div><div><div>        return super(Test, self).itemChange(change, new_value)</div></div><div><div><br></div></div><div><div>    def type(self) -> int:</div></div><div><div>        return QGraphicsItem.UserType + 100</div></div><div><div><br></div></div><div><div><br></div></div><div><div>app = QApplication(sys.argv)</div></div><div><div>scene = QGraphicsScene()</div></div><div><div>view = QGraphicsView(scene)</div></div><div><div>view.show()</div></div><div><div><br></div></div><div><div>parent1 = QGraphicsRectItem()</div></div><div><div>parent2 = QGraphicsRectItem()</div></div><div><div>scene.addItem(parent1)</div></div><div><div>scene.addItem(parent2)</div></div><div><div><br></div></div><div><div>test = Test(parent1)</div></div><div><div><br></div></div><div><div>print("Old parent:", test.parentItem())</div></div><div><div>test.setParentItem(parent2)</div></div><div><div>print("New parent:", test.parentItem())</div></div><div><div><br></div></div><div><div>sys.exit(app.exec_())</div></div></blockquote><div><div><br></div><div><br></div><div>The output shows that the reparenting failed (shows None). With suitable print statements, you can see that Test.itemChange(ParentChange, value) is called, but the return of super() itemChange() is None (which is like making the object refuse to reparent itself, except that the original parentage is not restored). The setParentItem() returns None. In our actual app, the reparented item appears in the scene away from the intended parent, and does not move with parent. </div><div><br></div><div>Now comment out the @pyqtSlot decoration, reparenting works. Or, use a different type of arg for pyqtSlot like int or list (or even QWidget), works. The setParentItem() returns parent. There are other types that cause failure too (like QGraphicsItem) when used in the decorator. </div><div><br></div><div>We tried the sip.cast() mentioned in <a href="https://riverbankcomputing.com/pipermail/pyqt/2012-August/031819.html">https://riverbankcomputing.com/pipermail/pyqt/2012-August/031819.html</a>, but that did not help (the super().itemChange() still returns None). My colleague <a href="http://stackoverflow.com/questions/38925044/parentitem-returns-none-not-expected">posted to stackoverflow</a> with similar script but I'm posting for him here since he is not on this mailing list! </div><div><br></div><div>If anyone can try this in PyQt 5.7 and let us know if the bug is gone, that would be good enough since upgrading to that version is on our short-term roadmap. </div><div><br></div><div>If the bug is still in latest 5.7 binary release, I'm really hoping someone can suggest a workaround that would allow us to continue to use itemChange, setParentItem and QPushButton or QGraphicsItem as arg to pyqtSlot decorator.</div><div><br></div><div>Best. </div><div><div><div class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div dir="ltr"><div><font size="2" style="font-size:small">Oliver</font><div style="font-size:small"><font size="1">Open Source contributions: <a href="http://pubsub.sf.net/" style="color:rgb(17,85,204)" target="_blank">PyPubSub</a>,</font><span style="font-size:x-small"> </span><a href="https://github.com/schollii/nose2pytest" style="color:rgb(17,85,204);font-size:x-small" target="_blank">nose2pytest</a><span style="font-size:x-small">,</span><span style="font-size:x-small"> L</span><a href="http://lua-icxx.sf.net/" style="font-size:x-small;color:rgb(17,85,204)" target="_blank">ua-iCxx</a><span style="font-size:x-small">, </span><a href="http://iof.sf.net/" style="font-size:x-small;color:rgb(17,85,204)" target="_blank">iof</a></div><div style="font-size:small"><font size="1"><a href="http://stackoverflow.com/users/869951/schollii" style="color:rgb(17,85,204)" target="_blank">StackOverflow</a> contributions</font></div></div><div><font size="1"><br></font></div><div></div></div></div></div></div></div></div>
</div></div></div>