PyQt 正确使用 emit() 和 pyqtSignal()
PyQt proper use of emit() and pyqtSignal()
我正在阅读一些关于 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' 参数有何不同。
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 个变量
class Example(QWidget):
my_signal = pyqtSignal(int)
pyqtSignal
的参数定义了将在该信号上 emit
的对象类型,因此在这种情况下,您可以
self.my_signal.emit(1)
emit can be reimplemented to send specific signal values to the slot
function. It is also not yet clear why I would need to send different
values from previously existing signal methods.
您通常不应发出内置信号。您应该只需要发出您定义的信号。在定义信号时,可以定义不同类型的不同签名,槽可以选择连接到哪个签名。例如,您可以这样做
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
)
我正在阅读一些关于 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' 参数有何不同。 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 个变量
class Example(QWidget):
my_signal = pyqtSignal(int)
pyqtSignal
的参数定义了将在该信号上 emit
的对象类型,因此在这种情况下,您可以
self.my_signal.emit(1)
emit can be reimplemented to send specific signal values to the slot function. It is also not yet clear why I would need to send different values from previously existing signal methods.
您通常不应发出内置信号。您应该只需要发出您定义的信号。在定义信号时,可以定义不同类型的不同签名,槽可以选择连接到哪个签名。例如,您可以这样做
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
)