pythonsignalsqt4slotqt-connection

Python qt4 - passing arguments in QtCore.QObject.connect


I want to react to a mouse click on a QLabel.
To achieve this I have redefined the method mouseReleaseEvent of QLabel.
I want to pass two arguments to the slot:

But I can only pass one parameter. Either QtGui.QMouseEvent or the ID.
The combination does not work.

# -*- coding: utf-8 -*-

import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import pyqtSignal

class ExtendedQLabel(QtGui.QLabel):
    
    #labelClickSignal_1 = pyqtSignal(QtGui.QMouseEvent)
    labelClickSignal_1 = pyqtSignal(QtGui.QMouseEvent, int)
    labelClickSignal_2 = pyqtSignal()
 
    def __init(self, parent):
        QtGui.QLabel.__init__(self, parent)
        
    # redefinition 
    def mouseReleaseEvent(self, event):
        
        #self.labelClickSignal_1.emit(event)
        self.labelClickSignal_1.emit(event, 0)
        self.labelClickSignal_2.emit()
        

class Test(QtGui.QMainWindow):

    def __init__(self, parent=None):
        
        QtGui.QMainWindow.__init__(self, parent)
        
        self.names = ['Test1', 'Test2', 'Test3']

        self.centralWidget = QtGui.QWidget()
        self.setCentralWidget(self.centralWidget)
        
        self.grid = QtGui.QGridLayout(self.centralWidget)
        
        row = 0
        for name in self.names:
            self.addLabel(name, row)
            row = row + 1
            
    def addLabel(self, name, row):
       
        label = ExtendedQLabel(name)
        
        # QtGui.QMouseEvent is automatically passed to the slot
        label.labelClickSignal_1.connect(self.onLabelClicked_1)
        
        # The row ID is passed to the slot
        label.labelClickSignal_2.connect(lambda id = row: 
                                 self.onLabelClicked_2(id))
                                 
        # *This does not work*
        label.labelClickSignal_1.connect(lambda id = row: 
                                 self.onLabelClicked_3(QtGui.QMouseEvent, id))
                                 
        self.grid.addWidget(label, row, 1)
       
        row = row + 1
        
    def onLabelClicked_1(self, event):
        
        if event.button() == QtCore.Qt.RightButton:
            print('right')
        else:
            print('left')

    def onLabelClicked_2(self, id):
        
        print('Label {0} clicked'.format(id))
        
    def onLabelClicked_3(self, event, id):

        # *This does not work*
        if event.button() == QtCore.Qt.RightButton:
            print('right {0}'.format(id))
        else:
            print('left {0}'.format(id))

def main():        
    app = QtGui.QApplication(sys.argv)
    
    t = Test()
    t.show()
    
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

Solution

  • Ok, since your code had several pieces that did not work I rewrote the important Parts to achieve what you want. Please Note that I use PySide and not PyQt. This means you have to change the importe Statements and the Signal back to PyQt Notation. The rest is explained in the code.

    import sys
    from PySide import QtGui, QtCore
    
    class ExtendedQLabel(QtGui.QLabel):
    
        #Signal that emits on MouseRelease
        labelClickSignal_1 = QtCore.Signal(QtGui.QMouseEvent, int)
    
        # init to -1
        labelId = -1
    
        # This is the new Constructor, Please note the double underscore 
        # before and behind `init`
        def __init__(self, parent, labelId):
            self.labelId = labelId
            QtGui.QLabel.__init__(self, parent)
    
        # emit labelClickSignal
        def mouseReleaseEvent(self, event):
            self.labelClickSignal_1.emit(event, self.labelId)
    
    
    class Test(QtGui.QMainWindow):
    
        def __init__(self, parent=None):
    
           # same as yours [...]
    
        def addLabel(self, name, row):
    
            # please note the added argument
            label = ExtendedQLabel(name,row)
    
            # connect the signal
            label.labelClickSignal_1.connect(self.onLabelClicked_1)
    
            self.grid.addWidget(label, row, 1)
    
            row = row + 1
    
        def onLabelClicked_1(self, event,labelId):    
            if event.button() == QtCore.Qt.RightButton:
                print('right')
                print(labelId)
            else:
                print('left')
                print(labelId)
    

    OLD ANSWER You have to define your Signal to support your two arguments:

    labelClickSignal_1 = pyqtSignal(QtGui.QMouseEvent,int)
    

    See here for additional information.

    Example from the docs:

    from PyQt4.QtCore import QObject, pyqtSignal
    
    class Foo(QObject):
    
        # This defines a signal called 'closed' that takes no arguments.
        closed = pyqtSignal()
    
        # This defines a signal called 'rangeChanged' that takes two
        # integer arguments.
        range_changed = pyqtSignal(int, int, name='rangeChanged')
    
        # This defines a signal called 'valueChanged' that has two overloads,
        # one that takes an integer argument and one that takes a QString
        # argument.  Note that because we use a string to specify the type of
        # the QString argument then this code will run under Python v2 and v3.
        valueChanged = pyqtSignal([int], ['QString'])