如何将lambda函数与pyqt“连接”一起使用。当小部件在循环中安装时,功能?
我正在PYQT项目中创建一个依赖情况的小部件列表(在这里,它以小部件类型的列表表示)。我不知道每种类型所需的小部件的数量,也不知道它们的类型和小部件的数量。
创建它们并不复杂,但是当用户想要更改它们时,我必须抓住它们的新价值时会遇到麻烦。
这是我问题的最低可再现示例:
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QCheckBox, QSpinBox, QWidget
import sys
class MyWidget(QWidget):
def __init__(self, widgetList):
super(QWidget, self).__init__()
self.widgetList = widgetList
layout = QVBoxLayout()
for widgetNumber in range(len(widgetList)):
if widgetList[widgetNumber] == 'QCheckBox':
widget = QCheckBox()
widget.stateChanged.connect(lambda: self.argumentChanged(widgetNumber, widget.isChecked()))
elif widgetList[widgetNumber] == 'QSpinBox':
widget = QSpinBox()
widget.valueChanged.connect(lambda: self.argumentChanged(widgetNumber, widget.value()))
layout.addWidget(widget)
self.setLayout(layout)
def argumentChanged(self, widgetNumber, value):
print("The widget number", widgetNumber, "that is a", self.widgetList[widgetNumber], "has been modified! New value:", value)
def window():
app = QApplication(sys.argv)
widgetList = ['QCheckBox', 'QCheckBox', 'QSpinBox']
widget = MyWidget(widgetList)
widget.show()
sys.exit(app.exec_())
if __name__ == '__main__':
window()
在这种情况下,lambda函数中的widgetnumber的价值将始终是循环的最后一次迭代。因此,如果我有4个小部件,我将在每个lambda函数中具有3个值。目的是具有当前小部件的值。
我还试图将lambda函数的表达式更改为这些:
lambda widgetNumber: self.argumentChanged(widgetNumber, widget.value()))
但是情况变得陌生:当增加旋转框的值时,小部件数字在增加,而在减少它时反之亦然。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
lambda内使用的变量始终在执行时评估:
widgetnumber
Will 始终是for循环中的最后一个值。此外,信号可以具有参数,如果您在lambda中使用位置参数,则该参数将是该信号发射时的值:
lambda widgetnumber:
将导致spinbox值或状态。复选框。如果您需要“静态”参数,则需要使用关键字参数。由于信号有参数,因此也无需再次调用getter:
请记住,只有在没有其他情况下才能使用lambdas, simpler ( clearer 或 >清洁器)解决方案。
在这种情况下,我们可以使用
sender()
QT提供的功能,该功能返回发出信号的对象。在下面的示例中,我简化了整个循环,并使用a custom属性直接在小部件上设置数字(请注意,也可以使用一个基本属性,但属性与QT更一致)。
The variables used inside a lambda are always evaluated at execution:
widgetNumber
will always be the last value in the for loop.Also, signals can have arguments, and if you use a positional argument in the lambda, that argument will be the value of that signal when it's emitted:
lambda widgetNumber:
will result in the spinbox value or the state of the check box.If you need "static" arguments, you need to use keyword arguments. Since the signal has arguments, there's also no need to call the getter again:
Remember that lambdas should be preferably used only when there is no other, simpler (clearer or cleaner) solution.
In this case, we can use the
sender()
function provided by Qt, which returns the object that emitted the signal.In the following example I've simplified the whole loop, and used a custom property to set the number directly on the widget (note that also a basic attribute could be used, but properties are more consistent with Qt).
因此,这里发生的事情
是:
widgetNumber
与循环的封装中使用的变量相同。到发出
循环的上述widget.statechanged
信号时,已经结束(显然),
widgetnumber
is3
。这是因为
value echanged
信号通过新值的整数值为您的函数/插槽作为第一个参数(
widgetNumber
参数),然后将其传递到self.argument.argument.argumentChanged
中。为了将
widgetnumber
的值保持在循环的每次迭代期间,您需要使用widgetnumber
作为[lambda]函数的默认参数。默认参数将在首次定义函数时评估,而不是每次调用时,因此您可以访问widgetNumber
在循环的每次迭代期间[lambda]函数时的内容。请注意,您需要使用嵌套功能。如果您只尝试具有一个默认参数的一个函数,则该参数将被设置为小部件的更改值,因为QT5将其作为第一个参数传递。
外部函数是具有
widgetnumber
作为其默认参数的一个功能,只需定义一个内部函数,然后返回(不调用)。它们是否功能都没关系。嵌套的lambdas很难阅读。这很令人困惑,但请参阅:
另请参见为什么在具有不同值的循环中定义的lambdas都返回相同的结果?
So what's happening here:
is that
widgetNumber
is the same variable used in the enclosingfor
loop. By the time thewidget.stateChanged
signal is emitted, the aforementionedfor
loop has already ended (obviously), andwidgetNumber
is3
.That's because the
valueChanged
signal passes the new value's integer value into your function/slot as the first argument (thewidgetNumber
parameter), which is then passed intoself.argumentChanged
.In order to keep the value of
widgetNumber
to what it was during each iteration of the loop, you need to usewidgetNumber
as the default argument of the [lambda] function. Default arguments are evaluated when the function is first defined, not each time it is called, so you can access whatwidgetNumber
was at the time of the [lambda] function during each iteration of the loop.Note that you need to use a nested function. If you try to just have one function with a default argument, the argument will be set as the widget's changed value, since Qt5 passes it as the first argument.
The outer function, which is the one with
widgetNumber
as its default argument, simply defines an inner function, and returns that (without calling it). It doesn't matter if they're lambda functions or not. Having nested lambdas is just difficult to read.It's pretty confusing, but have a play around with this:
See also Why do lambdas defined in a loop with different values all return the same result?