在PyQt中,您可以使用QtCore.pyqtSignal()
创建自定义信号.
我尝试自己实现Observer模式来代替pyqtSignal
它来规避它的一些限制(例如没有动态创建).
它在很大程度上起作用,至少有一个区别.
这是我到目前为止的实施
class Signal: def __init__(self): self.__subscribers = [] def emit(self, *args, **kwargs): for subs in self.__subscribers: subs(*args, **kwargs) def connect(self, func): self.__subscribers.append(func) def disconnect(self, func): try: self.__subscribers.remove(func) except ValueError: print('Warning: function %s not removed from signal %s'%(func,self))
注意到的一件事是工作方式的差异QObject.sender()
.
我通常会保持清醒sender()
,但如果它的工作方式不同,那么其他事情也可能如此.
对于常规pyqtSignal
信号,发送方始终是最接近信号链的小部件.
在底部的示例中,您将看到两个对象,ObjectA
和ObjectB
.ObjectA
转发信号ObjectB
并最终由Window接收.
有pyqtSignal
,接收的对象sender()
是ObjectA
,即转发信号的对象ObjectB
.
使用上面的Signal类,接收的对象是ObjectB
链中的第一个对象.
为什么是这样?
完整的例子
# Using PyQt5 here although the same occurs with PyQt4 from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * class Window(QWidget): def __init__(self, parent=None): super(Window, self).__init__(parent) object_a = ObjectA(self) object_a.signal.connect(self.listen) layout = QBoxLayout(QBoxLayout.TopToBottom, self) layout.addWidget(object_a) def listen(self): print(self.sender().__class__.__name__) class ObjectA(QWidget): signal = Signal() # signal = pyqtSignal() def __init__(self, parent=None): super(ObjectA, self).__init__(parent) object_b = ObjectB() object_b.signal.connect(self.signal.emit) layout = QBoxLayout(QBoxLayout.TopToBottom, self) layout.addWidget(object_b) class ObjectB(QPushButton): signal = Signal() # signal = pyqtSignal() def __init__(self, parent=None): super(ObjectB, self).__init__('Push me', parent) self.pressed.connect(self.signal.emit) if __name__ == '__main__': import sys app = QApplication([]) win = Window() win.show() sys.exit(app.exec_())
更多参考
编辑:
道歉,我应该提供一个用例.
以下是使用pyqtSignals的一些限制:
pyqtSignal:
..只适用于类属性
..不能在已经实例化的类中使用
..必须预先指定您要发出的数据类型
..产生不支持关键字参数的信号
..产生实例化后无法修改的信号
因此,我主要关注的是将它与基类一起使用.
考虑以下.
列表类型容器窗口小部件的6个不同窗口小部件共享相同的接口,但外观和行为略有不同.基类提供基本变量和方法以及信号.
使用pyqtSignal,您必须首先从QObject或QWidget继承您的基类.
问题是,如果其中一个小部件也继承自QPushButton,则这些都不能用作混合或多重继承.
class PinkListItem(QPushButton, Baseclass)
使用上面的Signal类,您可以改为创建没有任何先前继承的类(或只是对象)的基类,然后将它们用作任何派生子类的混合.
小心不要提出关于多重继承或混合是否良好的问题,或者是否有其他方法来实现同样的事情.我也很喜欢你的反馈,但也许这不是那个地方.
我更感兴趣的是在Signal类中添加位以使其与pyqtSignal产生的类似.
编辑2:
刚刚注意到了一个投票,所以这里有更多的用例.
发射时的关键词参数.
signal.emit(5)
可以写成
signal.emit(velocity=5)
与Builder一起使用或使用任何类型的依赖注入
def create(type): w = MyWidget() w.my_signal = Signal() return w
松耦合
我正在使用PyQt4和PyQt5.使用上面的Signal类,我可以为它们生成基类,而不依赖于它们.