Python PyQt5信号插槽装饰器示例
我目前正在创建一个类,该类生成pyqtSignal(int)和pyqtSlot(int)。困难在于创建发出特定值的信号 假设我想要生成类似于以下简单示例的内容: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(
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()修饰符pyqtlot(int)
- 你能举例说明什么时候有必要吗
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_())
这里只需要解决两个问题:
Q_类型
告诉我它的类型是PyQt5.QtCore.pyqtWrapperType
,而它应该是PyQt5.qtwidts.QSlider
QSlider
发送我希望它发送的更改值呢。我相信这就是emit()
发挥作用的地方,但对于它如何有用,我还没有足够的知识。
我知道如果我希望信号将值35传递给slot函数,我可以进行某种函数调用self.sld.emit(35)
。问题不是如何实现,而是在哪里实现此功能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的命名方案一致。)