我们可以在pyside中发出基类的信号吗?

cfi*_*cfi 5 super signals-slots pyside python-3.x

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

工作用例组成

实例化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_()
Run Code Online (Sandbox Code Playgroud)

这是一个小巧但有效的示例,它打开了一个最小的空白窗口,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)
Run Code Online (Sandbox Code Playgroud)

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

通过更换来挽救 super()

有趣的是,如果两个类都更改为不使用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)
Run Code Online (Sandbox Code Playgroud)

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

较小的更新: 使用继承并super()删除所有与信号相关的代码时,此示例可以打开窗口且不会出现段错误。因此似乎有迹象表明super()初始化和信号的组合会导致问题。

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

(这是带有CPython 3.3.1解释器的Ubuntu 13.04系统上的Qt 4.8.4,Pyside 1.1.2)

cfi*_*cfi 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_()
Run Code Online (Sandbox Code Playgroud)