通过信号调用函数将默认键控参数更改为“False".为什么?

2022-01-12 00:00:00 python pyqt pyqt5 qpushbutton

问题描述

当通过信号连接调用函数时

mybutton.clicked.connect(myfunction)

调用该函数时,其所有参数都设置为 False.即使已设置默认参数.这是预期的行为吗?

下面的代码显示了一个简单的示例.对于我的特殊情况,将所有参数设置为 False 并不是一个大问题,因为我可以简单地用 if 语句来捕捉它.但是,我认为了解为什么以这种方式实施它可能对进一步的项目有所帮助.

这个简单的程序显示了我所期望的行为.

def 函数(foo=None):打印(富)功能()

<块引用>

但是,在这个最小的 Qt 示例中,函数参数不再是None",而是False".

导入系统从 PyQt5.QtWidgets 导入 QMainWindow、QGridLayout、QWidget、QPushButton、QApplication类主窗口(QMainWindow):def __init__(self):QMainWindow.__init__(self)centralWidget = QWidget(self)self.setCentralWidget(centralWidget)gridLayout = QGridLayout(self)centralWidget.setLayout(gridLayout)btn = QPushButton("按钮",self)gridLayout.addWidget(btn)btn.clicked.connect(self.function)def 函数(自我,foo=None):打印(富)如果 __name__ == "__main__":应用程序 = QApplication(sys.argv)mainWin = MainWindow()mainWin.show()sys.exit(app.exec_())

<块引用>

错误

我想,问题是:我是否必须忍受在我的函数中没有可用的默认值(即,一旦我注意到它们被设置为 False,我是否需要重置它们)还是有任何更聪明的方法处理它?<​​/p>

解决方案

clicked是一个重载信号,即它们是2个同名信号不同签名.

clicked = QtCore.pyqtSignal([], [bool])# 点击 = QtCore.pyqtSignal()# clicked = QtCore.pyqtSignal(bool)

有关详细信息,请阅读此答案.

建立连接时,PyQt 确定将使用哪个信号,在这种情况下,您的函数的参数类似于第二种形式,因此信号将发送布尔值 False,在您的情况下,它将替换默认值.

如果您不希望这种情况发生,那么您必须使用 @QtCore.pyqtSlot() 装饰器,以便它不会向您发送任何参数,因此您的函数使用默认参数.

导入系统从 PyQt5 导入 QtCore、QtWidgets类 MainWindow(QtWidgets.QMainWindow):def __init__(self, parent=None):超级(主窗口,自我).__init__(父)centralWidget = QtWidgets.QWidget()self.setCentralWidget(centralWidget)gridLayout = QtWidgets.QGridLayout(centralWidget)btn = QtWidgets.QPushButton("按钮")gridLayout.addWidget(btn)btn.clicked.connect(self.function)@QtCore.pyqtSlot()def 函数(自我,foo=None):打印(富)如果 __name__ == "__main__":应用程序 = QtWidgets.QApplication(sys.argv)mainWin = MainWindow()mainWin.show()sys.exit(app.exec_())

输出:

When calling a function via a signal connection as in

mybutton.clicked.connect(myfunction)

the function is called with all its arguments set to False. Even though default arguments have been set. Is this the expected behavior?

The code below shows a simple example. For my particular case having all arguments set to False is not a big issue as I can simply catch it with an if statement. However I feel that knowledge on why it is implemented this way may be helpful for further projects.

This simple program shows the behavior I would expect.

def function(foo=None):
    print(foo)

function()

None

With this minimal Qt example however, the functions argument is no longer 'None', but 'False'.

import sys
from PyQt5.QtWidgets import QMainWindow, QGridLayout, QWidget, QPushButton, QApplication

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        centralWidget = QWidget(self)
        self.setCentralWidget(centralWidget)
        gridLayout = QGridLayout(self)
        centralWidget.setLayout(gridLayout)
        btn = QPushButton("button",self)
        gridLayout.addWidget(btn)
        btn.clicked.connect(self.function)

    def function(self, foo=None):
        print(foo)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainWin = MainWindow()
    mainWin.show()
    sys.exit( app.exec_() )

False

The question, i guess, is: Do I have to live with no having the default values available in my functions (i.e. do I need to reset them once I notice that they were set to False) or is there any smarter way to handle it?

解决方案

clicked is an overloaded signal, that is, they are 2 signals with the same name and with different signatures.

clicked = QtCore.pyqtSignal([], [bool])
# clicked = QtCore.pyqtSignal()
# clicked = QtCore.pyqtSignal(bool)

For more detail read this answer.

When the connection is made PyQt determines which of the signals will use, in this case the arguments of your function are similar to the second form so the signal will send the boolean False, and in your case it will replace the default value.

If you do not want that to happen then you must force PyQt to use the first form using the @QtCore.pyqtSlot() decorator so that it does not send you any parameter and therefore your function uses the default parameter.

import sys
from PyQt5 import QtCore, QtWidgets


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        centralWidget = QtWidgets.QWidget()
        self.setCentralWidget(centralWidget)
        gridLayout = QtWidgets.QGridLayout(centralWidget)
        btn = QtWidgets.QPushButton("button")
        gridLayout.addWidget(btn)
        btn.clicked.connect(self.function)

    @QtCore.pyqtSlot()
    def function(self, foo=None):
        print(foo)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    mainWin = MainWindow()
    mainWin.show()
    sys.exit(app.exec_())

Output:

None

相关文章