問(wèn)題描述
我正在閱讀有關(guān) PyQt5 的一些文檔,以提出一個(gè)簡(jiǎn)單的信號(hào)槽機(jī)制.由于設(shè)計(jì)考慮,我已經(jīng)停下來(lái)了.
考慮以下代碼:
導(dǎo)入系統(tǒng)從 PyQt5.QtCore 導(dǎo)入 (Qt, pyqtSignal)從 PyQt5.QtWidgets 導(dǎo)入(QWidget、QLCDNumber、QSlider、QVBoxLayout, QApplication)類示例(QWidget):def __init__(self):超級(jí)().__init__()self.initUI()def printLabel(self, str):打印(字符串)定義日志標(biāo)簽(自我,str):'''記錄到文件'''經(jīng)過(guò)定義 initUI(自我):lcd = QLCDNumber(self)sld = QSlider(Qt.Horizo??ntal, self)vbox = QVBoxLayout()vbox.addWidget(lcd)vbox.addWidget(sld)self.setLayout(vbox)#冗余連接sld.valueChanged.connect(lcd.display)sld.valueChanged.connect(self.printLabel)sld.valueChanged.connect(self.logLabel)self.setGeometry(300, 300, 250, 150)self.setWindowTitle('信號(hào)和槽')自我展示()如果 __name__ == '__main__':應(yīng)用程序 = QApplication(sys.argv)ex = 示例()sys.exit(app.exec_())
要跟蹤對(duì)滑塊所做的更改,我只需打印并記錄所做的更改.我不喜歡代碼的地方是我需要調(diào)用 sld.valueChanged
插槽三次以將相同的信息發(fā)送到 3 個(gè)不同的插槽.
是否可以創(chuàng)建我自己的 pyqtSignal
將整數(shù)發(fā)送到單個(gè)插槽函數(shù).反過(guò)來(lái)讓槽函數(shù)發(fā)出需要進(jìn)行的更改?
- 也許我不完全理解
emit()
的用途,因?yàn)樵?PyQt Signal-Slot 文檔.我們給出的只是一個(gè)如何實(shí)現(xiàn)不帶參數(shù)的emit
的示例.
我想做的是創(chuàng)建一個(gè)處理發(fā)射函數(shù)的函數(shù).考慮以下幾點(diǎn):
導(dǎo)入系統(tǒng)從 PyQt5.QtCore 導(dǎo)入 (Qt, pyqtSignal)從 PyQt5.QtWidgets 導(dǎo)入(QWidget、QLCDNumber、QSlider、QVBoxLayout, QApplication)類示例(QWidget):def __init__(self):超級(jí)().__init__()#創(chuàng)建信號(hào)self.val_Changed = pyqtSignal(int, name='valChanged')self.initUI()定義 initUI(自我):lcd = QLCDNumber(self)sld = QSlider(Qt.Horizo??ntal, 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('信號(hào)和槽')自我展示()def handle_LCD(自我,文本):'''日志'''打印(文本)'''將 val_Changed 連接到 lcd.display'''如果 __name__ == '__main__':應(yīng)用程序 = QApplication(sys.argv)ex = 示例()sys.exit(app.exec_())
這里顯然存在一些嚴(yán)重的設(shè)計(jì)缺陷.我無(wú)法理解函數(shù)調(diào)用的順序.而且我沒(méi)有正確實(shí)現(xiàn) pyqtSignal
.不過(guò),我確實(shí)相信正確陳述以下 3 點(diǎn)將有助于我制作出合適的應(yīng)用程序:
- 對(duì)于預(yù)定義的信號(hào):將信號(hào)發(fā)送到槽函數(shù).可以重新實(shí)現(xiàn) Slot 以使用信號(hào)值.
- 生成帶有一些參數(shù)的
pyqtSignal
對(duì)象.目前尚不清楚這些參數(shù)的用途是什么以及它們與發(fā)射"參數(shù)有何不同. emit
可以重新實(shí)現(xiàn)以將特定的信號(hào)值發(fā)送到槽函數(shù).目前還不清楚為什么我需要發(fā)送與以前存在的信號(hào)方法不同的值.
隨意完全改變我正在嘗試做的代碼,因?yàn)槲疫€沒(méi)有弄清楚它是否屬于良好的風(fēng)格.
您可以定義自己的插槽(任何 python 可調(diào)用)并將其連接到信號(hào),然后從該插槽調(diào)用其他插槽.
類示例(QWidget):def __init__(self):超級(jí)().__init__()self.initUI()def printLabel(self, str):打印(字符串)定義日志標(biāo)簽(自我,str):'''記錄到文件'''經(jīng)過(guò)@QtCore.pyqtSlot(int)def on_sld_valueChanged(自我,價(jià)值):self.lcd.display(值)self.printLabel(值)self.logLabel(值)定義 initUI(自我):self.lcd = QLCDNumber(self)self.sld = QSlider(Qt.Horizo??ntal, 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('信號(hào)和槽')
另外,如果你想定義自己的信號(hào),它們必須定義為類變量
類示例(QWidget):my_signal = pyqtSignal(int)
pyqtSignal
的參數(shù)定義了將在該信號(hào)上發(fā)出
的對(duì)象類型,因此在這種情況下,您可以這樣做
self.my_signal.emit(1)
<塊引用>
emit 可以重新實(shí)現(xiàn)以將特定的信號(hào)值發(fā)送到插槽功能.目前還不清楚為什么我需要發(fā)送不同的來(lái)自先前存在的信號(hào)方法的值.
您通常不應(yīng)該發(fā)出內(nèi)置信號(hào).您應(yīng)該只需要發(fā)出您定義的信號(hào).定義信號(hào)時(shí),可以定義不同類型的不同簽名,插槽可以選擇要連接的簽名.例如,您可以這樣做
my_signal = pyqtSignal([int], [str])
這將定義一個(gè)具有兩個(gè)不同簽名的信號(hào),并且一個(gè)插槽可以連接到任何一個(gè)
@pyqtSlot(int)def on_my_signal_int(自我,價(jià)值):斷言 isinstance(值,int)@pyqtSlot(str)def on_my_signal_str(自我,價(jià)值):斷言 isinstance(值,str)
在實(shí)踐中,我很少重載信號(hào)簽名.我通常只會(huì)創(chuàng)建兩個(gè)具有不同簽名的單獨(dú)信號(hào),而不是重載相同的信號(hào).但它存在并在 PyQt 中得到支持,因?yàn)?Qt 具有以這種方式重載的信號(hào)(例如 QComboBox.currentIndexChanged
)
I am reading through some documentation on PyQt5 to come up with a simple signal-slot mechanism. I have come to a halt due to a design consideration.
Consider the following code:
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_())
To track the changes made to the slider, I simply print and log the changes made. What I do not like about the code is that I am required to call the sld.valueChanged
slot thrice to send the same information to 3 different slots.
Is it possible to create my own pyqtSignal
that sends an integer to a single slot function. And in turn have the slot function emit the changes that need to be made?
- Maybe I don't fully understand the purpose of
emit()
because there are no good examples of it's purpose in the PyQt Signal-Slot docs. All we're given is an example of how to implement anemit
with no parameters.
What I would like to do is create a function that handles the emit function. Consider the following:
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_())
There are obviously some serious design flaws here. I cannot wrap my head around the order of function calls. And I am not implementing pyqtSignal
correctly. I do however believe that correctly stating the following 3 points will help me produce a proper app:
- For a predefined signal: send the signal to the slot function. Slot can be reimplemented to use the signal values.
- Produce
pyqtSignal
object with some parameters. It is not yet clear what the purpose of these parameters are and how they differ from 'emit' parameters. 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.
Feel free to completely alter the code for what I am trying to do because I have not yet figured out if its in the realm of good style.
You can define your own slot (any python callable) and connect that to the signal, then call the other slots from that one slot.
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')
Also, if you want to define your own signals, they have to be defined as class variables
class Example(QWidget):
my_signal = pyqtSignal(int)
The arguments to pyqtSignal
define the types of objects that will be emit
'd on that signal, so in this case, you could do
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.
You generally shouldn't be emitting the built in signals. You should only need to emit signals that you define. When defining a signal, you can define different signatures with different types, and slots can choose which signature they want to connect to. For instance, you could do this
my_signal = pyqtSignal([int], [str])
This will define a signal with two different signatures, and a slot could connect to either one
@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)
In practice, I rarely overload signal signatures. I would normally just create two separate signals with different signatures rather than overloading the same signal. But it exists and is supported in PyQt because Qt has signals that are overloaded this way (eg. QComboBox.currentIndexChanged
)
這篇關(guān)于PyQt 正確使用 emit() 和 pyqtSignal()的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!