我是PySide的新手,并试图弄清楚如何优雅地创造出有效的信号扇出;即一个看起来像Slot to容器类的doodad,因此可以connect()编辑,并简单地将该信号转发到包含的类,最好不会在语法或性能上增加太多开销。
让我们采取一个完全人为的例子:
class TripleCheckBox(QWidget):
setCheckState = Signal(int)
def __init__(self, parent):
super().__init__(parent)
self.checks = [QCheckBox(x, self) for x in ['One', 'Two', 'Three']]
[self.setCheckState.connect(x) for x in self.checks]
class MainWindow(QWidget):
def __init__(self):
self.chk = QCheckBox('Alpha', self)
self.btn = QPushButton('Push', self)
self.tri = TripleCheckBox(self)
self.chk.stateChanged.connect(self.tri.setCheckState)
self.btn.clicked.connect(self.clearChecks)
def clearChecks(self):
self.tri.setCheckState(0)
所以,这完成了我正在寻找的大部分内容。来自Alpha复选框的stateChanged信号击中TripleCheckBox上的信号端口,然后重新转发为一,二和三,并且(我相信)完全在Qt库中完成,而不必在库代码和Python之间来回反弹
但MainWindow.ClearChecks()
不起作用。对于真正的QCheckBox,setCheckState是一个Slot,因此是一个函数,可以用传统的函数语法调用。但是TripleCheckBox上的setCheckState是一个Signal,所以必须“调用”为self.tri.setCheckState.emit(0)
这在语法上很丑陋,但也有一些难看的可持续性含义。如果我有一个QCheckBox,我可以将setCheckState视为一个函数。如果我有一个TripleCheckBox,我必须将它视为一个信号,即使它所做的只是包装3个QCheckBox。
理想情况下,TripleCheckBox.setCheckState就像一个信号,它只有__call__
方法,调用/是emit
。但是你不能从Signal继承。
我可以想到几种不太优雅的方法来做到这一点,所有这些方法都涉及大量的代码复制和adhocery。但这是一些非常基本的东西,肯定有一个优雅的答案。正确?
答案 0 :(得分:1)
在您的示例中使用自定义信号是多余的,并且使代码不必要地复杂化。
鉴于其名称和预期用途,TripleCheckBox.setCheckState
应该是一个插槽而不是一个信号。信号本身不应该做任何事情:它只是一个事件发生(或即将发生)的通知。信号应该没有直接的副作用,任何广播它的对象都不应该关心它一旦被发射后会产生什么后果(如果有的话)。
出于这个原因,行self.tri.setCheckState(0)
无意义作为信号(尽管它作为一个插槽)。另一方面,像self.tri.stateChanged.emit(0)
这样的东西会有意义(虽然不一定在那个特定的上下文中)。
鉴于以上几点,这里有一种重写你的例子的方法:
from PySide import QtCore, QtGui
class CheckBoxSet(QtGui.QWidget):
def __init__(self, labels, parent=None):
super(CheckBoxSet, self).__init__(parent)
layout = QtGui.QVBoxLayout(self)
self.checkboxes = []
for label in labels:
checkbox = QtGui.QCheckBox(label, self)
layout.addWidget(checkbox)
self.checkboxes.append(checkbox)
def setCheckState(self, state=0):
state = QtCore.Qt.CheckState(state)
for checkbox in self.checkboxes:
checkbox.setCheckState(state)
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
layout = QtGui.QVBoxLayout(self)
self.chk = QtGui.QCheckBox('Alpha', self)
self.btn = QtGui.QPushButton('Push', self)
self.tri = CheckBoxSet('One Two Three'.split(), self)
layout.addWidget(self.chk)
layout.addWidget(self.btn)
layout.addWidget(self.tri)
self.chk.stateChanged.connect(self.tri.setCheckState)
self.btn.clicked.connect(self.clearChecks)
def clearChecks(self):
self.tri.setCheckState(0)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 300, 200)
window.show()
sys.exit(app.exec_())