5

是否可以从基类继承信号并在派生类中将方法连接到它们?如果是,如何?

具有组合的工作测试用例

在 a 中实例化 a MyObjectMyWidget并且在小部件中对对象发出的信号作出反应。

from PySide.QtGui import QApplication, QMainWindow
from PySide.QtCore import QObject, QTimer, Signal
from PySide.QtGui import QLabel

class MyObject(QObject):
    sig = Signal()

    def __init__(self, parent=None):
        super().__init__(parent)
        QTimer.singleShot(3000, self.alert)
        QTimer.singleShot(5000, self.exit)
    def alert(self):
        self.sig.emit()
    def exit(self):
        print('All done')
        exit(0)

class MyWidget(QLabel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.monitor = MyObject(self)
        self.monitor.sig.connect(self.update)
    def update(self):
        print(2)

app = QApplication([])
w = MyWidget()
w.show()
app.exec_()

这是一个小而有效的示例,它打开一个最小的空窗口,self.monitor由小部件实例化的对象在 3 和 5 秒后发出一个计时器信号。第一个提示小部件只向控制台打印一个数字,第二个信号导致应用程序退出。

继承失败的测试用例

对于继承,只有小部件类更改为:

class MyWidget(MyObject, QLabel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.sig.connect(self.update)
    def update(self):
        print(2)

如果在控制台中运行,则不会打印任何内容,但会发生分段错误。为什么?这可以挽救吗?

通过更换挽救super()

有趣的是,如果将两个类都更改为 not use super(),该示例将再次起作用:

class MyObject(QObject):
    sig = Signal()

    def __init__(self, parent=None):
        QObject.__init__(self, parent)
        QTimer.singleShot(3000, self.alert)
        QTimer.singleShot(5000, self.exit)
    def alert(self):
        self.sig.emit()
    def exit(self):
        print('All done')
        exit(0)

class MyWidget(MyObject, QLabel):
    def __init__(self, parent=None):
        MyObject.__init__(self, parent)
        QLabel.__init__(self, parent)
        self.sig.connect(self.update)
    def update(self):
        print(2)

一般来说我更喜欢使用super(),但也许我需要重新考虑?我特意链接到两篇关于super()在 Python 中使用的有争议的文章。现在会对如何super()正确使用 pyside 感兴趣,或者解释为什么它在 pyside 中根本不起作用。

次要更新: 当使用继承super()但删除所有与信号相关的代码时,该示例的工作原理是它确实打开了窗口并且没有段错误。所以似乎有一些迹象表明super()初始化和信号的组合会导致问题。

次要更新2: ..并且在注释掉self.sig.connect窗口时启动并且仅在 5 秒信号触发以退出应用程序时出现段错误。

(这是 Ubuntu 13.04 系统上的 Qt 4.8.4、Pyside 1.1.2 和 CPython 3.3.1 解释器)

4

2 回答 2

4

Qt 不支持多重继承QObjects,同样的限制也适用于 PySide 和 PyQt。尽管有时有一些方法可以解决此限制,但尝试创建具有两个或多个QObject基类的子类通常不是一个好主意。

对于信号的继承,使用简单的非QObjectmixin 可能是最好的方法——尽管我认为这个解决方案只适用于 PySide;对于 PyQt4,信号只能在QObject子类上定义。

更新

后一个限制在 PyQt5 中被删除:现在可以在不继承自QObject.

于 2013-10-18T18:40:54.497 回答
1

到目前为止,我能想到的唯一解决方案——或者更确切地说是解决方法——满足标准(a)继承和(b)使用super()是防止钻石关系受到用户 tcaswell 评论的启发。

对于我的用例,必须保留任何消费者类的继承(对于自定义小部件)。另一方面,保证 - 目前 - 所有消费类都将(间接)从QObject. 因此没有必要从 派生MyObjectQObject尽管这实际上创建了一个真正的抽象 MixIn 类:它不能独立使用,并且对消费类有接口要求。我不确定我是否喜欢它。

这是工作代码:

from PySide.QtGui import QApplication, QMainWindow
from PySide.QtCore import QObject, QTimer, Signal
from PySide.QtGui import QLabel

class MyObject:
    sig = Signal()

    def __init__(self, parent=None):
        super().__init__(parent)
        QTimer.singleShot(3000, self.alert)
        QTimer.singleShot(5000, self.exit)
    def alert(self):
        self.sig.emit()
    def exit(self):
        print('All done')
        exit(0)

class MyWidget(MyObject, QLabel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.sig.connect(self.update)
    def update(self):
        print(2)


app = QApplication([])

w = MyWidget()
w.show()


app.exec_()
于 2013-10-18T16:11:06.007 回答