将插槽连接到来自类派生的所有对象的信号

Posted

技术标签:

【中文标题】将插槽连接到来自类派生的所有对象的信号【英文标题】:Connect a slot to signals from all objects derived from a class 【发布时间】:2021-02-25 20:01:34 【问题描述】:

我刚开始使用 PyQt5,希望能得到一些帮助。我有一个小部件 W,它响应从某个类 C 派生的所有对象的信息。小部件 W 只能由 C 类的对象更新,并且在更新期间,它必须知道哪个特定对象触发了它。

问题是 C 类的对象可能会在整个程序过程中继续创建。是否可以将信号/槽范式应用于此问题?

到目前为止我的想法:

    理想情况下,我会将 W 上的插槽连接到 C 上的类变量。但是,Qt 不允许将信号作为类变量。 我可以使用集合对象 CO,这样任何新对象 C 都必须通过该对象的接口创建。然后我在这个对象上定义一个信号,它将连接到 W 上的一个插槽。然而,这很丑,因为 CO 的存在只是为了解决这个问题。 我可以完全放弃信号/槽范例,而只需将 W 的回调(槽)添加到 C 上的类变量中。然后,每当创建新对象 C 时,它就已经具有对回调的引用。李>

【问题讨论】:

【参考方案1】:

一种可能的解决方案是使用元类:

import sys

from PyQt5 import QtCore, QtWidgets


class MetaC(type(QtCore.QObject), type):
    def __call__(cls, *args, **kw):
        obj = super().__call__(*args, **kw)
        for receiver in cls.receivers:
            obj.signal.connect(receiver)
        return obj


class C(QtCore.QObject, metaclass=MetaC):
    signal = QtCore.pyqtSignal()
    receivers = []

    @classmethod
    def register(cls, slot):
        cls.receivers.append(slot)


class C1(C):
    def test(self):
        self.signal.emit()


class C2(C1):
    pass


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        C.register(self.foo)

    def foo(self):
        print("foo")


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()

    c1, c2 = C1(), C2()

    QtCore.QTimer.singleShot(1000, c1.test)
    QtCore.QTimer.singleShot(5 * 1000, c2.test)

    QtCore.QTimer.singleShot(6 * 1000, QtCore.QCoreApplication.quit)

    sys.exit(app.exec_())

【讨论】:

以上是关于将插槽连接到来自类派生的所有对象的信号的主要内容,如果未能解决你的问题,请参考以下文章

Qt将信号连接到插槽

使用 PySide2 将 python 信号连接到 QML ui 插槽

Qt:如何将不同类的静态信号连接到插槽?

C++ 和 QML:将 QML 信号连接到 C++ 插槽

如何将信号连接到 2 个共享库之间的插槽

QT将不同类的信号和插槽连接到主窗口类?