Python PyQt5信号插槽装饰器示例

Python PyQt5信号插槽装饰器示例,python,qt,pyqt,decorator,signals-slots,Python,Qt,Pyqt,Decorator,Signals Slots,我目前正在创建一个类,该类生成pyqtSignal(int)和pyqtSlot(int)。困难在于创建发出特定值的信号 假设我想要生成类似于以下简单示例的内容: import sys from PyQt5.QtCore import (Qt, pyqtSignal, pyqtSlot) from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, QVBoxLayout, QApplication) class Example(

我目前正在创建一个类,该类生成pyqtSignal(int)和pyqtSlot(int)。困难在于创建发出特定值的信号

假设我想要生成类似于以下简单示例的内容:

import sys
from PyQt5.QtCore import (Qt, pyqtSignal, pyqtSlot)
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)

    @pyqtSlot(int)
    def on_sld_valueChanged(self, value):
        self.lcd.display(value)
        self.printLabel(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')
        self.show()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())
关于上述代码,我的第一个问题是:

  • 当删除
    pyqtlot(int)
    对代码没有影响时,为什么要使用pyqtlot()修饰符
  • 你能举例说明什么时候有必要吗
出于特定原因,我想使用pyqtSignal()工厂生成自己的信号,并获得了适当的文档。然而,唯一的问题是,它并不能为如何发射特定信号提供坚实的基础。 以下是我试图做的,但却发现自己迷失了方向:

  • 创建一个元类,允许实现许多不同类型的QWidget子类
  • 让元类产生自己的信号,可以从类外部调用
  • 这就是我想要的:

    from PyQt5.QtWidgets import QPushButton, QWidget
    from PyQt5.QtCore import pyqtSignal, pyqtSlot
    from PyQt5.QtWidgets import QSlider
    
    def template(Q_Type, name: str, *args):
        class MyWidget(Q_Type):
    
            def __init__(self) -> None:
                super().__init__(*args)
                self._name = name
    
            def setSignal(self,type):
                self.signal = pyqtSignal(type)
    
            def callSignal(self):
                pass
    
        return MyWidget
    
    如你所见。我给小部件起了一个名字,因为我发现这个名字很有用,我还尝试从类中实例化QWidget以简化代码

    下面是我希望一个主类如何生成第一个示例中的小部件:

    import sys
    from PyQt5.QtCore import (Qt, pyqtSignal, pyqtSlot)
    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)
    
        @pyqtSlot(int)
        def sld_valChanged(self, value):
            self.lcd.display(value)
            self.printLabel(value)
    
        def initUI(self):
    
            #instantiate the QWidgets through template class
            self.lcd = template(QLCDNumber,'lcd_display')
            self.sld = template(QSlider, 'slider', Qt.Horizontal)
    
            #create signal
            #self.sld.setSignal(int)
    
            vbox = QVBoxLayout()
            vbox.addWidget(self.lcd)
            vbox.addWidget(self.sld)
    
            self.setLayout(vbox)
    
            #connect signal - this won't send the value of the slider
            #self.sld.signal.connect(self.sld_valChanged)
            self.sld.valueChanged.connect(self.sld_valChanged)
    
            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_())
    
    这里只需要解决两个问题:

  • 模板元类设置不正确,我无法从元类中实例化QWidget。
    Q_类型
    告诉我它的类型是
    PyQt5.QtCore.pyqtWrapperType
    ,而它应该是
    PyQt5.qtwidts.QSlider
  • 即使我通过模板类创建了一个newSignal,我如何让
    QSlider
    发送我希望它发送的更改值呢。我相信这就是
    emit()
    发挥作用的地方,但对于它如何有用,我还没有足够的知识。 我知道如果我希望信号将值35传递给slot函数,我可以进行某种函数调用
    self.sld.emit(35)
    。问题不是如何实现,而是在哪里实现此功能
  • 我可能完全偏离了基准,过度思考了解决方案,请随意更正我的代码,这样我就可以让我的信号发出滑块的值

    删除pyqtSlot(int)时为什么要使用pyqtSlot()修饰符 对代码没有影响?你能举个例子说明什么时候会发生吗 必要吗

    已在您的中解决,但我将再次重复

    虽然PyQt4允许在以下情况下将任何可调用的Python用作插槽: 连接信号时,有时需要明确标记 Python方法作为QT槽,并提供C++签名 信息技术PyQt4提供pyqtSlot()函数修饰符来完成此操作

    将信号连接到修饰过的Python方法也具有 减少使用的内存量的优势,并且 更快

    此外,正如在中所述,不能将信号创建为实例变量,它们必须是类属性

    这是行不通的

    def setSignal(self,type):
        self.signal = pyqtSignal(type)
    
    一定是

    class MyWidget(QWidget):
        signal = pyqtSignal(int)
    
    创建一个元类,允许实现许多不同类型的QWidget子类

    您不能为
    QObjects
    定义元类,因为它们已经使用了自己的元类(这就是允许信号魔法工作的原因)。但是,您仍然可以使用该函数创建
    QObject
    子类工厂

    def factory(QClass, cls_name, signal_type):
        return type(cls_name, (QClass,), {'signal': pyqtSignal(signal_type)})
    
    MySlider = factory(QSlider, 'MySlider', int)
    self.sld = MySlider(Qt.Horizontal)
    self.sld.signal.connect(self.on_signal)
    
    让元类产生自己的信号,可以从类外部调用

    简而言之,不要这样做。你不应该在课堂外发出信号。上面的工厂示例不是很有用,因为您没有在这些类上定义自定义方法来发出这些信号。通常,这就是如何利用自定义信号

    class MyWidget(QWidget):
        colorChanged = pyqtSignal()
    
        def setColor(self, color):
            self._color = color
            self.colorChanged.emit()
    
    
    class ParentWidget(QWidget):
    
        def __init__(self):
            ...
            self.my_widget = MyWidget(self)
            self.my_widget.colorChanged.connect(self.on_colorChanged)
            # This will cause the colorChanged signal to be emitted, calling on_colorChanged
            self.my_widget.setColor(Qt.blue)
    
        def on_colorChanged(self):
            # do stuff
    

    然后我的问题是:如何组织代码,特别是在处理许多小部件时。简单地将大量小部件放在一个主类中似乎有点草率。一个典型的应用程序将有几十个小部件,都包含在一个窗口或对话框中。这一点也不马虎。看看官方的Qt和PySide示例应用程序。他们会让你了解应用程序是如何组织的。假设我想把颜色变化记录到一个文件中。(我想做的是记录每个小部件的每个信号,并调用外部框架)。我知道因此我可以在
    setColor
    中调用日志函数,但要从另一个框架调用函数,我需要
    colorChanged
    color
    传递到
    on\u colorChanged
    中。我对示例类进行了编辑,以显示我正在尝试做什么。tnx,它有帮助:)使用@pyqtSignal()不推荐使用。仅使用@pyqtSlot()。检查文档,了解如何按预期方式使用它。不要重新发明轮子。(如果你问我,@pyqtSlot()应该命名为@pyqtSlot(),以与PyQt的命名方案一致。)