首先,如果使用Qt的signal-slot autowire机制,则使用该方法QMetaObject::connectSlotsByName()
,因此此行为是由于该函数从 C++ 到 Python 的转换所致,在 C++ 中,QMetaObject::connectSlotsByName() 函数仅连接到槽,但在 Python 中,它扩展为调用不是槽的函数。
问题是当你点击时是一个重载信号,在 C++ 的情况下允许你使用默认参数来实现:
void QAbstractButton::clicked(bool checked = false)
但在 python 2 中必须使用签名:
clicked = QtCore.pyqtSignal([], [bool])
因此,在 PyQt 与插槽建立的连接中,它用于QMetaObject::connectSlotsByName()
使用的是QMetaObject
使用获取签名的对象的QMetaMethod
,但是如果它不是插槽,您将无法获取该信息,因此连接相当于一次调用。
如果是@pyqtSlot()
有以下签名:
@pyqtSlot()
def on_btnSlot_clicked(self):
print('slotted function call')
PyQt 建立的连接如下:
self.btnSlot.clicked.connect(self.on_btnSlot_clicked)
但如果签名者@pyqtSlot(bool)
is:
@pyqtSlot(bool)
def on_btnSlot_clicked(self, checked):
print('slotted function call', checked)
PyQt 建立的连接如下:
self.btnSlot.clicked[bool].connect(self.on_btnSlot_clicked)
但在它连接到不是槽的函数的情况下,它不会考虑这些元素,因为它使用QMetaObject
,因此它将与所有可能的签名建立连接。
self.btnSlot.clicked[bool].connect(self.on_btnFunc_clicked)
self.btnSlot.clicked.connect(self.on_btnFunc_clicked)
综上所述:
When QMetaObject::connectSlotsByName(...)
被使用,如果它连接到@pyqtSlot(...)
,签名得到验证。如果信号连接到的函数不是@pyqtSlot(...)
它们将与所有可能的签名连接,因此如果信号因 n 个签名而过载,它将被调用 n 次。
你必须使用@pyqtSlot() http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html#the-pyqtslot-decorator避免了前面的问题,因为它具有快速和节省资源的优点。