[PyQt] QObject::​sender() returns the original object that sent the signal

Yuya Nishihara yuya at tcha.org
Mon Apr 6 13:55:52 BST 2015


On Mon, 6 Apr 2015 15:35:08 +0800 (CST), redstone-cold wrote:
> test code
> https://bpaste.net/show/79b893f0d9fd
> 
> The PyQt4 version of the same code , self.sender() in downloadProgress,
> no matter decorated with @pyqtSlot(int, int) or not, returns a QNetworkReply,
> the direct object that sent the signal, when on_deleteTasks_triggered(),

Probably because reply.abort() doesn't emit finished() immediately on your
PyQt4 environment. As I said before, I see the same issue on both PyQt4 and
PyQt5.

The problem is that sender() returns the sender of the 1st signal

 a) if the 1st slot is triggered directly by Qt (decorated as @pyqtSlot)
 b) and if the 2nd slot is triggered in that slot
 c) and if the 2nd connection is managed by PyQt (not decorated as @pyqtSlot)
 d) and if the 2nd slot is bound to the same object as the 1st slot

I suggest using pyqtSlot consistently.

class MainDialog(QDialog):
    def __init__(self, parent=None):
        super(MainDialog, self).__init__(parent)
        t = QTimer(self, singleShot=True)
        t.timeout.connect(self.openDialog)
        t.start(0)

    @pyqtSlot()
    def openDialog(self):
        dlg = QDialog(self, windowTitle='Close me')
        dlg.finished.connect(self._dialogFinished)
        dlg.exec_()  # blocking
        #dlg.show()  # non-blocking

    #@pyqtSlot()
    def _dialogFinished(self):
        print self.sender()  # should be a QDialog, but actually a QTimer
        assert isinstance(self.sender(), QDialog)

app = QApplication([])
dlg = MainDialog()
dlg.show()
app.exec_()


More information about the PyQt mailing list