【发布时间】:2013-10-16 20:09:17
【问题描述】:
是否可以从基类继承信号并在派生类中将方法连接到它们?如果是,怎么做?
使用组合工作测试用例
在MyWidget 中实例化MyObject,并在小部件中对对象发出的信号作出反应。
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() 来挽救
有趣的是,如果将两个类都更改为不使用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)
Generally I prefer to use super(),但也许我需要reconsider?我特意链接了两篇关于在 Python 中使用 super() 的有争议的文章。现在会对如何在 pyside 中正确使用 super() 或解释为什么它在 pyside 中根本不起作用感兴趣。
小更新:
当使用继承和super() 但删除所有与信号相关的代码时,该示例的工作原理是它确实打开了窗口并且没有段错误。所以似乎有一些迹象表明super() 初始化和信号的组合会导致问题。
小更新2:
..当注释掉 self.sig.connect 时,窗口会启动,并且只有在 5 秒信号触发退出应用程序时才会出现段错误。
(这是 Ubuntu 13.04 系统上的 Qt 4.8.4,Pyside 1.1.2,带有 CPython 3.3.1 解释器)
【问题讨论】:
-
它会崩溃还是干净地退出?我认为
sig.connect()就足够了,因为信号应该是类级别而不是实例级别属性。 -
@tcaswell:根据我的定义,Segfault 是崩溃并且没有干净的退出。信号总是在对象之间连接。 This doc 没有明确说明,但没有列出替代方案。而且,考虑一下,连接类的信号和槽是没有意义的,因为这意味着这些类的所有对象都是连接的。实例可以连接并相互交谈,在这方面,类只是类型定义。类型可以定义如何相互通信的协议,但它们实际上不能通信。对象可以。
-
不清楚您是否遇到了段错误。包装层执行了很深的魔法来将 python 映射到 c++ 并返回。如果您遇到段错误,则您将 c++ 层推入错误状态。
-
仔细看一下,我怀疑问题是你在 c++ 层得到了菱形图。尽管 python 可以应付它,
pyside对象是 c++ 对象的一个薄包装,并且它们的实例化变得一团糟。我对super的理解是,它就像 c++ 中的 const 正确性一样,如果您在任何地方使用它,它会很好地工作,而如果您只是偶尔使用它会造成极大的痛苦。 -
也就是说,我认为如果你不混入
QLabel,它会起作用。
标签: python-3.x pyside signals-slots super