我正在阅读有关PyQt5的一些文档,以提出一种简单的信号插槽机制。由于设计方面的考虑,我停了下来。

考虑以下代码:

import sys
from PyQt5.QtCore import (Qt, pyqtSignal)
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,
    QVBoxLayout, QApplication)


class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def printLabel(self, str):
        print(str)

    def logLabel(self, str):
        '''log to a file'''
        pass

    def initUI(self):

        lcd = QLCDNumber(self)
        sld = QSlider(Qt.Horizontal, self)

        vbox = QVBoxLayout()
        vbox.addWidget(lcd)
        vbox.addWidget(sld)

        self.setLayout(vbox)

        #redundant connections
        sld.valueChanged.connect(lcd.display)
        sld.valueChanged.connect(self.printLabel)
        sld.valueChanged.connect(self.logLabel)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Signal & slot')
        self.show()


if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

为了跟踪对滑块所做的更改,我仅打印并记录所做的更改。我对代码不满意的是,我需要三次调用sld.valueChanged插槽才能将相同的信息发送到3个不同的插槽。

是否可以创建我自己的pyqtSignal,将其整数发送到单个插槽函数。反过来,插槽功能是否发出需要进行的更改?
  • 也许我不太了解emit()的目的,因为PyQt Signal-Slot docs中没有很好的例子说明它的目的。我们所提供的只是一个如何实现不带参数的emit的示例。

  • 我想做的是创建一个处理emit函数的函数。考虑以下:
    import sys
    from PyQt5.QtCore import (Qt, pyqtSignal)
    from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,
        QVBoxLayout, QApplication)
    
    
    class Example(QWidget):
    
        def __init__(self):
            super().__init__()
    
            #create signal
            self.val_Changed = pyqtSignal(int, name='valChanged')
    
            self.initUI()
    
        def initUI(self):
    
            lcd = QLCDNumber(self)
            sld = QSlider(Qt.Horizontal, self)
    
            vbox = QVBoxLayout()
            vbox.addWidget(lcd)
            vbox.addWidget(sld)
    
            self.setLayout(vbox)
    
            sld.val_Changed.connect(self.handle_LCD)
            self.val_Changed.emit()
    
            self.setGeometry(300, 300, 250, 150)
            self.setWindowTitle('Signal & slot')
            self.show()
    
        def handle_LCD(self, text):
            '''log'''
            print(text)
            '''connect val_Changed to lcd.display'''
    
    if __name__ == '__main__':
    
        app = QApplication(sys.argv)
        ex = Example()
        sys.exit(app.exec_())
    

    这里显然存在一些严重的设计缺陷。我无法绕过函数调用的顺序。而且我没有正确实现pyqtSignal。但是,我确实相信正确说明以下3点将有助于我制作出合适的应用程序:
  • 对于预定义的信号:将信号发送到插槽功能。插槽可以重新实现以使用信号值。
  • 生成带有一些参数的pyqtSignal对象。尚不清楚这些参数的目的是什么以及它们与“发射”参数有何不同。
  • emit可以重新实现,以将特定信号值发送到插槽功能。还不清楚我为什么需要从以前存在的信号方法中发送不同的值。

  • 随意为我要尝试的代码完全更改代码,因为我还没有弄清楚它是否属于好的样式。

    最佳答案

    您可以定义自己的插槽(任何可调用的python)并将其连接到信号,然后从该插槽中调用其他插槽。

    class Example(QWidget):
    
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def printLabel(self, str):
            print(str)
    
        def logLabel(self, str):
            '''log to a file'''
            pass
    
        @QtCore.pyqtSlot(int)
        def on_sld_valueChanged(self, value):
            self.lcd.display(value)
            self.printLabel(value)
            self.logLabel(value)
    
        def initUI(self):
    
            self.lcd = QLCDNumber(self)
            self.sld = QSlider(Qt.Horizontal, self)
    
            vbox = QVBoxLayout()
            vbox.addWidget(self.lcd)
            vbox.addWidget(self.sld)
    
            self.setLayout(vbox)
            self.sld.valueChanged.connect(self.on_sld_valueChanged)
    
    
            self.setGeometry(300, 300, 250, 150)
            self.setWindowTitle('Signal & slot')
    

    另外,如果要定义自己的信号,则必须将它们定义为类变量
    class Example(QWidget):
        my_signal = pyqtSignal(int)
    
    pyqtSignal的参数定义了将在该信号上进行emit的对象的类型,因此在这种情况下,您可以
    self.my_signal.emit(1)
    



    通常,您不应该发出内置信号。您只需要发出定义的信号即可。定义信号时,可以定义具有不同类型的不同签名,插槽可以选择要连接到的签名。例如,您可以这样做
    my_signal = pyqtSignal([int], [str])
    

    这将定义一个具有两个不同签名的信号,并且一个插槽可以连接到任何一个
    @pyqtSlot(int)
    def on_my_signal_int(self, value):
        assert isinstance(value, int)
    
    @pyqtSlot(str)
    def on_my_signal_str(self, value):
        assert isinstance(value, str)
    

    实际上,我很少过载信号签名。通常,我只创建两个具有不同签名的单独信号,而不是使同一信号过载。但是它存在并在PyQt中受支持,因为Qt具有以这种方式过载的信号(例如 QComboBox.currentIndexChanged )

    关于python - PyQt正确使用emit()和pyqtSignal(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36434706/

    10-11 18:45