如何断言 PyQt5 信号的身份? [英] How do I assert the identity of a PyQt5 signal?
问题描述
我想断言 PyQt5 信号的身份.具体来说,我想检查来自给定 QPushButton
对象的 clicked
信号是否与存储在名为 signal
的变量中的信号相同.以下代码段说明了这种情况:
I'm in a situation where I want to assert the identity of a PyQt5 signal. Specifically, I want to check whether the clicked
signal from a given QPushButton
object is identical to a signal that is stored in a variable named signal
. The following snippet illustrates the situation:
from PyQt5.QtWidgets import QApplication, QPushButton
app = QApplication([])
widget = QPushButton()
signal = widget.clicked
widget.clicked == signal
Out[1]: False
widget.clicked is signal
Out[2]: False
id(widget.clicked) == id(signal)
Out[3]: False
如图所示,分别涉及==
、is
和id()
的三个比较都产生False
>,即他们无法断言左手和右手参数的同一性.
As shown, the three comparisons involving ==
, is
, and id()
respectively all produce False
, i.e. they fail to assert the identity of the left-hand and the right-hand argument.
有什么方法可以断言 widget.clicked
和 signal
引用的是同一个信号?
Is there any way to assert that widget.clicked
and signal
are referencing the same signal?
推荐答案
每次调用时都会创建作为实体的信号,因为它们代表不同的连接:
Signals as entities are created each time you invoke it as they represent a different connection:
In [1]: import sys
In [2]: from PyQt5 import QtWidgets
In [3]: app = QtWidgets.QApplication(sys.argv)
In [4]: button = QtWidgets.QPushButton()
In [5]: id(button.clicked)
Out[5]: 140150155639464
In [6]: id(button.clicked)
Out[6]: 140150154507528
In [7]: id(button.clicked)
Out[7]: 140150155640184
In [8]: id(button.clicked)
Out[8]: 140150155640504
In [9]: id(button.clicked)
Out[9]: 140150154510128
In [10]: id(button.clicked)
Out[10]: 140149427454320
因此,如果在同一个信号和插槽之间连接 100 次,并且在发出信号时,该插槽将被调用 100 次:
Therefore if you connect 100 times between the same signal and slot, and when the signal is emitted, the slot will be called 100 times:
import sys
from PyQt5 import QtCore, QtWidgets
def foo():
print("clicked")
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
button = QtWidgets.QPushButton("Press me")
button.show()
for _ in range(10):
button.clicked.connect(foo)
# the click is emulated
QtCore.QTimer.singleShot(1000, lambda: button.animateClick(500))
QtCore.QTimer.singleShot(2000, app.quit)
sys.exit(app.exec_())
输出:
clicked
clicked
clicked
clicked
clicked
clicked
clicked
clicked
clicked
clicked
所以直接解决你的问题是不可能的,但我认为你的目标是区分哪个对象发出调用插槽的信号,因为你可能有几个对象连接到同一个插槽,如果有一个解决方案:
So it will be impossible to solve your problem directly but I think that your goal is to discriminate which object that emitted the signal that calls the slot since you probably have several objects connected to the same slot, and for that if there is a solution:
如果插槽属于 QObject(或从 QObject 派生的类作为小部件),那么您可以使用 sender 方法获取发出信号的对象.
If the slot belongs to a QObject (or classes derived from QObject as the widgets) then you can use the sender method to obtain the object that emitted the signal.
import sys
from PyQt5 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.button_1 = QtWidgets.QPushButton("button 1")
self.button_1.clicked.connect(self.foo)
self.button_2 = QtWidgets.QPushButton("button 2")
self.button_2.clicked.connect(self.foo)
self.button_3 = QtWidgets.QPushButton("button 3")
self.button_3.clicked.connect(self.foo)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.button_1)
lay.addWidget(self.button_2)
lay.addWidget(self.button_3)
@QtCore.pyqtSlot()
def foo(self):
button = self.sender()
if button is self.button_1:
print("button_1")
elif button is self.button_2:
print("button_2")
elif button is self.button_3:
print("button_3")
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
2.将对象作为附加参数传递
2.1 拉姆达函数<小时>
2. Pass the object as an additional parameter
2.1 lambda functionimport sys
from PyQt5 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.button_1 = QtWidgets.QPushButton("button 1")
self.button_1.clicked.connect(lambda *args, b=self.button_1 : self.foo(b))
self.button_2 = QtWidgets.QPushButton("button 2")
self.button_2.clicked.connect(lambda *args, b=self.button_2 : self.foo(b))
self.button_3 = QtWidgets.QPushButton("button 3")
self.button_3.clicked.connect(lambda *args, b=self.button_3 : self.foo(b))
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.button_1)
lay.addWidget(self.button_2)
lay.addWidget(self.button_3)
def foo(self, button):
if button is self.button_1:
print("button_1")
elif button is self.button_2:
print("button_2")
elif button is self.button_3:
print("button_3")
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
2.1 functools.partial 函数<小时>
2.1 functools.partial function
import sys
from PyQt5 import QtCore, QtWidgets
from functools import partial
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.button_1 = QtWidgets.QPushButton("button 1")
self.button_1.clicked.connect(partial(self.foo, self.button_1))
self.button_2 = QtWidgets.QPushButton("button 2")
self.button_2.clicked.connect(partial(self.foo, self.button_2))
self.button_3 = QtWidgets.QPushButton("button 3")
self.button_3.clicked.connect(partial(self.foo, self.button_3))
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.button_1)
lay.addWidget(self.button_2)
lay.addWidget(self.button_3)
def foo(self, button):
if button is self.button_1:
print("button_1")
elif button is self.button_2:
print("button_2")
elif button is self.button_3:
print("button_3")
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
<小时>
在我的情况下,如果可以使用,我更喜欢使用 sender,然后是 functools.partial,最后是 lambda 方法
In my case I prefer to use sender if I can use it, then functools.partial and finally lambda methods
这篇关于如何断言 PyQt5 信号的身份?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!