【发布时间】:2016-07-27 11:57:03
【问题描述】:
我目前正在创建一个生成 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_())
我对上述代码的第一个问题是:
- 当删除
pyqtSlot(int)对代码没有影响时,为什么还要使用 pyqtSlot() 装饰器? - 您能否举例说明何时需要这样做?
出于特定原因,我想使用 pyqtSignal() 工厂生成我自己的信号,并获得了不错的文档here。然而,唯一的问题是,simple example 并没有为如何发出特定信号提供坚实的基础。
这是我正在尝试做但发现自己迷路的事情:
- 创建一个允许实现许多不同类型的 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_())
这里只有2个问题需要解决:
- 模板元类设置不正确,我无法从元类中实例化 QWidget。
Q_Type告诉我它的类型是PyQt5.QtCore.pyqtWrapperType,而它应该是PyQt5.QtWidgets.QSlider。 - 即使我正在通过模板类创建一个 newSignal,我如何让
QSlider发送我希望它发送的更改值。我相信这就是emit()发挥作用的地方,但对它的用途还没有足够的了解。 我知道如果我希望信号将值 35 传递给 slot 函数,我可以进行某种函数调用self.sld.emit(35)。问题不是如何实现,而是我应该在哪里实现这个功能?
我可能完全不合时宜并且过度考虑了解决方案,请随时更正我的代码,以便我可以让我的信号发出滑块的值。
【问题讨论】:
-
不推荐使用@pyqtSignal()。仅使用 @pyqtSlot()。查看文档如何按预期方式使用它。不要重新发明轮子。 (如果你问我,@pyqtSlot() 应该命名为 @pyQtSlot() 以与 PyQt 的命名方案保持一致。)
标签: python qt pyqt decorator signals-slots