pythonpython-3.xeventspyqt

Connecting to events of another widget


This is most likely a duplicate question, but I have to ask it because other answers aren't helping in my case, since I am new to pyqt (switched from tkinter few days ago).

I am wondering if is it possible to connect to an event of a widget like this:

 self.lineEdit = QtGui.QLineEdit(self.frame)

 self.lineEdit.keyReleaseEvent(lambda: someFunction(QtCore.Qt.Key_A ))

 self.lineEdit.setObjectName(_fromUtf8("lineEdit"))

 self.horizontalLayout.addWidget(self.lineEdit)

and then...

def someFunction(event):
    print(event)
    ...

My question is how to bind to a specific event from another widget, and connect that event with a function - like btn.clicked.connect(function_goes_here).

In tkinter it's something be like this:

self.Entry.bind("<KeyRelease-a>", lambda event: someFunction(event))

Solution

  • There are a number of different ways to achieve this. A generic way to listen to all events for a given widget, is to install an event-filter on it. All protected functions have a corresponding event type that can be accessed in this way:

    class MainmWindow(QMainWindow):
        def __init__(self):
            ...
            self.lineEdit = QLineEdit(self.frame)
            self.lineEdit.installEventFilter(self)
    
        def eventFilter(self, source, event):
            if source is self.lineEdit:
                if event.type() == QEvent.KeyRelease:
                    print('key release:', event.key())
                    # the following line will eat the key event
                    # return True
            return super(MainmWindow, self).eventFilter(source, event)
    

    Alternatively, you can sub-class the widget, re-implement the relevant event handler, and emit a custom signal:

    class LineEdit(QLineEdit):
        keyReleased = pyqtSignal(int)
    
        def keyReleaseEvent(self, event):
            self.keyReleased.emit(event.key())
            super(LineEdit, self).keyReleaseEvent(event)
    
    class MainmWindow(QMainWindow):
        def __init__(self):
            ...
            self.lineEdit = LineEdit(self.frame)
            self.lineEdit.keyReleased.connect(self.handleKeyRelease)
    
        def handleKeyRelease(self, key):
            print('key release:' key)
    

    A more hackish variation on this is to overwrite the method directly:

    class MainmWindow(QMainWindow):
        def __init__(self):
            ...
            self.lineEdit = QLineEdit(self.frame)
            self.lineEdit.keyReleaseEvent = self.handleKeyRelease
    
        def handleKeyRelease(self, event):
            print('key release:', event.key())
            QLineEdit.keyReleaseEvent(self.lineEdit, event)
    

    Note that if you don't want to invoke the default event handling, you can omit the call to the base-class method.