简体   繁体   中英

Binding event handlers in PyQT

Using PyQt5, there are certain event handlers which I can bind to my object, and others that only work if I implement them as methods. changeEvent and event are examples of the later type.

You can see in my example below that I can add a keyPressEvent handler to my widget programmatically, but I can not do the same thing for changeEvent .

from PyQt5 import QtGui, QtWidgets, QtCore

import types

def keyPressEvent(self, key: QtGui.QKeyEvent) -> None:
    #works
    print(key.isAutoRepeat())

def changeEvent(self, a0: QtCore.QEvent) -> None:
    #doesn't work
    print("bound change event", a0.type())


bindable = [keyPressEvent, changeEvent]

def bind_key_functions(target):
    for bound in bindable:
        setattr(target, bound.__name__, types.MethodType(bound, target))

class my_widget(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle("w1")
        bind_key_functions(self)


class my_widget2(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle("w2")

    def changeEvent(self, a0: QtCore.QEvent) -> None:
        #this does work
        print("derived change event", a0.type())

app = QtWidgets.QApplication([])
mw1 = my_widget()
mw1.show()
mw2 = my_widget2()
mw2.show()
app.exec_()

What makes the changeEvent different? how can I force it to behave as I want?

Using setattr to override methods is a bad choice as it is not very elegant and if you want to listen to the events of another QWidget then it is better to use an event filter.

from PyQt5 import QtGui, QtWidgets, QtCore


class Binder(QtCore.QObject):
    def __init__(self, qobject):
        super().__init__(qobject)
        self._qobject = qobject
        self.qobject.installEventFilter(self)

    @property
    def qobject(self):
        return self._qobject

    def eventFilter(self, obj, event):
        if self.qobject is obj:
            print(event.type(), event)

        return super().eventFilter(obj, event)


class My_Widget(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle("w1")
        Binder(self)


class My_Widget2(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle("w2")


app = QtWidgets.QApplication([])
mw1 = My_Widget()
mw1.show()
mw2 = My_Widget2()
mw2.show()
app.exec_()

On the other hand, it is not documented which methods can be assigned or not, so if you want to find the reason you must analyze the source code of sip and pyqt5. What little is pointed out is that PyQt5 creates a cache of the methods (it is not known when or what methods are stored in the cache).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM