pyqt 按钮自动绑定到 on_..._clicked 函数,无需连接或 pyqtSlot
Posted
技术标签:
【中文标题】pyqt 按钮自动绑定到 on_..._clicked 函数,无需连接或 pyqtSlot【英文标题】:pyqt button automatically binds to on_..._clicked function without connect or pyqtSlot 【发布时间】:2019-02-25 07:18:59 【问题描述】:我已经使用 pyqt5 和 qt-designer 几个星期了。我习惯于使用连接语句将信号连接到处理函数。
昨天我做了一段代码,它也自动将按钮点击信号连接到没有 pyqtSlot 装饰器的处理函数。
将 clicked 信号连接到函数导致单击按钮一次时执行该函数三次。
删除连接语句导致单击按钮一次时执行两次函数。
在函数中添加@pyqtSlot 会导致正常的一次性执行。
将处理函数重命名为 'on_button-name_clicked' 以外的其他名称也会导致正常的一次性执行。
以下代码显示了这种“自动连接”行为。
谁能解释为什么在没有 connect 或 pyqtSlot 的情况下发生这种自动连接双处理程序调用?
提前致谢,梅斯
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QMainWindow
from PyQt5.uic import loadUi
import sys
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
loadUi('MainWindowTestButton.ui', self)
self.show()
def on_pushButton_clicked(self):
print('clicked')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())
上面的代码打印出来
点击
点击
单击按钮一时。
这是示例中的 MainWindowTestButton.ui 文件
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindowTestButton</class>
<widget class="QMainWindow" name="MainWindowTestButton">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>70</x>
<y>60</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
【问题讨论】:
【参考方案1】:为什么要自动连接?
loadUi()
函数在内部调用 connectSlotsByName() 方法,如果某些方法具有以下结构,则该方法会自动连接:
C++:
void on_<object name>_<signal name>(<signal parameters>);
Python:
def on_<object name>_<signal name>(<signal parameters>):
在您的情况下,on_pushButton_clicked
方法满足该要求,因为您有一个对象名为 "pushButton"
的 QWidget
(继承自 QObject)按钮:
<widget class="QPushButton" name="pushButton">
有一个名为clicked
的信号。
为什么要两次调用同一个方法?
QPushButton 有一个被重载的 clicked 信号,也就是说有几个同名但参数不同的信号。如果the docs 被审核:
void QAbstractButton::clicked(bool checked = false)
虽然理解起来可能比较复杂,上面的代码相当于:
clicked = pyqtSignal([], [bool])
这类似于:
clicked = pyqtSignal()
clicked = pyqtSignal([bool])
所以总而言之 QPushButton 有 2 个 clicked 信号将连接到 on_pushButton_clicked 函数,所以当你按下按钮时,两个信号将通过调用相同的方法发出,这样 clicked 将被打印 2 次。
连接不考虑前一个信号是否使用相同的方法连接,因此手动连接将有 3 个连接(2 个不带参数单击的信号 [1 个自动单击,另一个手动单击],1 个使用信号点击参数),所以该方法将被调用 3 次。
当您使用装饰器@pyqtSlot
时,您正在指示签名(即参数的类型),因此connect 方法只会与与插槽签名匹配的信号进行连接,因此您不会再看到问题了因为你使用信号没有参数
【讨论】:
你好 eyllanesc。感谢您的出色而清晰的回答。它解释了我所描述的问题的所有方面。 你好@eyllanesc,不知道为什么装饰器在我的情况下似乎不起作用。我有以下代码:self.save_button.clicked.connect(self.on_save)
,在课堂上的某处有:@pyqtSlot() def on_save(self): print("LOL")
当我单击按钮时,“LOL”显示两次。我的语法不正确还是我遗漏了什么。以上是关于pyqt 按钮自动绑定到 on_..._clicked 函数,无需连接或 pyqtSlot的主要内容,如果未能解决你的问题,请参考以下文章