如何将自定义事件发送到PyQt中的事件循环

发布于 2021-01-29 14:55:56

我试图在PyQt中发出自定义事件。一个小部件将发出,另一个小部件将监听事件,但是两个小部件不需要关联。

在JavaScript中,我会这样做

// Component 1
document.addEventListener('Hello', () => console.log('Got it'))

// Component 2
document.dispatchEvent(new Event("Hello"))

编辑:我知道信号和插槽,但只知道如何在父级和子级之间使用它们。我如何在任意不相关的小部件之间使用这种机制(或其他机制)?

关注者
0
被浏览
88
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    在PyQt中,以下说明:

    document.addEventListener('Hello', () => console.log('Got it'))
    

    等价的

    document.hello_signal.connect(lambda: print('Got it'))
    

    以类似的方式:

    document.dispatchEvent(new Event("Hello"))
    

    等价的

    document.hello_signal.emit()
    

    但是最大的区别是“文档”对象的范围,因为连接是在全局元素之间。但是在PyQt中,该元素不存在。

    模拟您指出的行为的一种方法是创建一个全局对象:

    globalobject.py

    from PyQt5 import QtCore
    import functools
    
    @functools.lru_cache()
    class GlobalObject(QtCore.QObject):
        def __init__(self):
            super().__init__()
            self._events = {}
    
        def addEventListener(self, name, func):
            if name not in self._events:
                self._events[name] = [func]
            else:
                self._events[name].append(func)
    
        def dispatchEvent(self, name):
            functions = self._events.get(name, [])
            for func in functions:
                QtCore.QTimer.singleShot(0, func)
    

    main.py

    from PyQt5 import QtCore, QtWidgets
    from globalobject import GlobalObject
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
            button = QtWidgets.QPushButton(text="Press me", clicked=self.on_clicked)
            self.setCentralWidget(button)
    
        @QtCore.pyqtSlot()
        def on_clicked(self):
            GlobalObject().dispatchEvent("hello")
    
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
            GlobalObject().addEventListener("hello", self.foo)
            self._label = QtWidgets.QLabel()
            lay = QtWidgets.QVBoxLayout(self)
            lay.addWidget(self._label)
    
        @QtCore.pyqtSlot()
        def foo(self):
            self._label.setText("foo")
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w1 = MainWindow()
        w2 = Widget()
        w1.show()
        w2.show()
        sys.exit(app.exec_())
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看