[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pykde
Subject:    Re: [PyQt] Decorator weirdness
From:       Phil Thompson <phil () riverbankcomputing ! com>
Date:       2015-08-15 14:02:02
Message-ID: 75159419-8A52-4ACF-BF14-63243EA583EB () riverbankcomputing ! com
[Download RAW message or body]

On 15 Aug 2015, at 12:43 pm, Iosif Spulber <iosif.spulber@gmail.com> wrote:
> 
> Hi,
> 
> I am using PyQt4 4.10.4.
> 
> I'm a bit puzzled by the pyqtSlot decorator. All I can find in the docs is that it \
> potentially improves performance, but I'm witnessing actual different behaviour \
> depending on how I use it. 
> 1.  The decorator seems to properly disconnect slots when the object is deleted.
> 
> In the snippet below, a slot of a widget to be deleted is connected to a button's \
> click. If I close the SlotWidget and click the button, without the decorator I get \
> a: "RuntimeError: wrapped C/C++ object of type QLabel has been deleted".
> With the decorator, the signal is disconnected before the object is destroyed and \
> the click has no effect.
> 
> My conclusion thus is that it's quite important to decorate slots like this.
> 
> from PyQt4 import QtGui, QtCore
> 
> app = QtGui.QApplication([])
> 
> class SlotWidget(QtGui.QWidget):
> def __init__(self, parent=None):
> QtGui.QWidget.__init__(self, parent)
> 
> self.label = QtGui.QLabel('LABEL', parent=self)
> # Make sure the object is deleted so potential problems arise
> self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
> 
> # Without this decorator, when this widget is closed and the button is
> # clicked, you get a RuntimeError.
> @QtCore.pyqtSlot()
> def my_slot(self):
> print 'Label text: %s' % self.label.text()
> 
> class MyWidget(QtGui.QWidget):
> def __init__(self, parent=None):
> QtGui.QWidget.__init__(self, parent)
> 
> self.button = QtGui.QPushButton("Button", parent=self)
> self.slot_widget = SlotWidget(parent=None)
> self.slot_widget.show()
> 
> self.button.clicked.connect(self.slot_widget.my_slot)
> 
> if __name__ == "__main__":
> widget = MyWidget()
> 
> widget.show()
> app.exec_()

Worth looking at http://pyqt.sourceforge.net/Docs/PyQt5/incompatibilities.html#pyqt-v5-3


PyQt4 implements the "old" behaviour.

> 2.  Consider this mock example; here, I want to provide some base functionality for \
> my widgets, that involves connecting a signal to a slot. I don't want to inherit \
> from QObject since multiple inheritance from QObject creates all sorts of issues in \
> PyQt4. 
> What I notice is that decorating the slot leads to an error:
> "TypeError: connect() failed between timeout() and base_slot()".
> Even weirder, calling the Base constructor before the QWidget one ensures that the \
> slot is called properly.
> 
> So in this case it seems to be better not to decorate the slot, but it can lead to \
> problems (see 1.). 
> from PyQt4 import QtGui, QtCore
> 
> app = QtGui.QApplication([])
> 
> class Base(object):
> def __init__(self, timer):
> self.timer = timer
> self.timer.timeout.connect(self.base_slot)
> 
> # Remove the decorator -> works regardless of __init__ order
> @QtCore.pyqtSlot()
> def base_slot(self):
> print 'Fired!'

PyQt4 does not support pyqtSlot() in non-QObject classes. PyQt5 does...

http://pyqt.sourceforge.net/Docs/PyQt5/pyqt4_differences.html#new-style-signals-and-slots


> class MyWidget(QtGui.QWidget, Base):
> def __init__(self, timer, parent=None):
> # Switch the order -> works regardless of decorator
> QtGui.QWidget.__init__(self, parent)
> Base.__init__(self, timer)
> 
> self.button = QtGui.QPushButton("Button", parent=self)
> self.button.clicked.connect(self.derived_slot)
> 
> @QtCore.pyqtSlot()
> def derived_slot(self):
> print 'Preparing to fire...'
> self.timer.start(2000)
> 
> if __name__ == "__main__":
> timer = QtCore.QTimer()
> timer.setSingleShot(True)
> 
> widget = MyWidget(timer)
> 
> widget.show()
> app.exec_()
> 
> 3.  Are slots always supposed to be bound? (i.e., should all the slots have a self \
> first argument?)

They just need to be callables.

> 4.  I would expect that explicitly decorating the slot with (C++) types should \
> provide enough information to disambiguate between overloaded signals. E.g., if I \
> have a slot decorated with @QtCore.pyqtSlot(str) and connect it to \
> QComboBox.activated it connects to the int signal by default (I have to connect to \
> QComboBox.activated[str]).

Added to the PyQt5 TODO list (but not PyQt4).

Phil
_______________________________________________
PyQt mailing list    PyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic