Python 将信号中继到包含的小部件

Python 将信号中继到包含的小部件,python,pyside,signals-slots,Python,Pyside,Signals Slots,我是PySide的新手,我想知道如何优雅地创建一个有效的信号扇形输出;i、 e.一个doodad,对于容器类来说,它看起来像一个插槽,因此可以连接到,并简单地将该信号转发到包含的类,最好在语法或性能方面都不会增加太多开销 让我们举一个完全人为的例子: class TripleCheckBox(QWidget): setCheckState = Signal(int) def __init__(self, parent): super().__init__(par

我是PySide的新手,我想知道如何优雅地创建一个有效的信号扇形输出;i、 e.一个doodad,对于容器类来说,它看起来像一个插槽,因此可以连接到,并简单地将该信号转发到包含的类,最好在语法或性能方面都不会增加太多开销

让我们举一个完全人为的例子:

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上的信号端口,然后该端口重新广播为1、2和3,并且(我相信)完全在Qt库内部执行,而不必在库代码和Python之间来回跳转

但是
MainWindow.ClearChecks()
不起作用。对于真正的QCheckBox,setCheckState是一个插槽,因此是一个函数,可以使用常规函数语法调用。但是TripleCheckBox上的setCheckState是一个信号,因此必须“调用”为
self.tri.setCheckState.emit(0)

这在语法上是丑陋的,但也有一些丑陋的可维护性含义。如果我有一个QCheckBox,我可以将setCheckState作为一个函数来处理。如果我有一个TripleCheckBox,我必须把它当作一个信号,即使它所做的只是包装3个QCCheckBox

理想情况下,TripleCheckBox.setCheckState类似于一个信号,它只是有一个调用/is
emit
\u调用
方法。但你不能从信号中继承


我可以想出几种不雅观的方法来做到这一点,所有这些方法都涉及大量的代码复制和数据处理。但这是一些相当基本的东西,肯定有一个优雅的答案。对吗?

在您的示例中使用自定义信号是多余的,并且使代码变得不必要的复杂

鉴于其名称和预期用途,
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_())