Python 使用lambda表达式连接pyqt中的插槽
我试图用lambda函数连接插槽,但它没有按我预期的方式工作。在下面的代码中,我成功地正确连接了前两个按钮。对于后两个,我在一个循环中连接,这是错误的。我之前的某个人也有同样的问题(),但这个解决方案对我不起作用。我已经盯着屏幕看了半个小时,但我不知道我的代码有什么不同Python 使用lambda表达式连接pyqt中的插槽,python,lambda,pyqt,Python,Lambda,Pyqt,我试图用lambda函数连接插槽,但它没有按我预期的方式工作。在下面的代码中,我成功地正确连接了前两个按钮。对于后两个,我在一个循环中连接,这是错误的。我之前的某个人也有同样的问题(),但这个解决方案对我不起作用。我已经盯着屏幕看了半个小时,但我不知道我的代码有什么不同 class MainWindow(QtGui.QWidget): def __init__(self): super(QtGui.QWidget, self).__init__() ma
class MainWindow(QtGui.QWidget):
def __init__(self):
super(QtGui.QWidget, self).__init__()
main_layout = QtGui.QVBoxLayout(self)
# Works:
self.button_1 = QtGui.QPushButton('Button 1 manual', self)
self.button_2 = QtGui.QPushButton('Button 2 manual', self)
main_layout.addWidget(self.button_1)
main_layout.addWidget(self.button_2)
self.button_1.clicked.connect(lambda x:self.button_pushed(1))
self.button_2.clicked.connect(lambda x:self.button_pushed(2))
# Doesn't work:
self.buttons = []
for idx in [3, 4]:
button = QtGui.QPushButton('Button {} auto'.format(idx), self)
button.clicked.connect(lambda x=idx: self.button_pushed(x))
self.buttons.append(button)
main_layout.addWidget(button)
def button_pushed(self, num):
print 'Pushed button {}'.format(num)
按下前两个按钮会产生“按下按钮1”和“按下按钮2”,另外两个按钮都会产生“按下按钮错误”,尽管我预期的是3和4
我还没有完全理解lambda机制。到底是什么连接起来的?指向lambda生成的函数(在中替换了参数)的指针,或者每当信号触发时,lambda函数都会被计算?我也不确定在这里使用lambda会出现什么问题。我认为这是因为idx(设置自动按钮时的循环索引)超出了范围,不再包含正确的值 但我不认为你需要这样做。看起来使用lambda的唯一原因是,您可以将参数传递给button_pushed(),以确定它是哪个按钮。有一个函数
sender()
,可以在按钮按下()槽中调用,该槽用于识别发出信号的按钮
这里有一个例子,我认为它或多或少地符合你的拍摄目的:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class MainWindow(QWidget):
def __init__(self):
super(QWidget, self).__init__()
main_layout = QVBoxLayout(self)
self.buttons = []
# Works:
self.button_1 = QPushButton('Button 1 manual', self)
main_layout.addWidget(self.button_1)
self.buttons.append(self.button_1)
self.button_1.clicked.connect(self.button_pushed)
self.button_2 = QPushButton('Button 2 manual', self)
main_layout.addWidget(self.button_2)
self.buttons.append(self.button_2)
self.button_2.clicked.connect(self.button_pushed)
# Doesn't work:
for idx in [3, 4]:
button = QPushButton('Button {} auto'.format(idx), self)
button.clicked.connect(self.button_pushed)
self.buttons.append(button)
main_layout.addWidget(button)
def button_pushed(self):
print('Pushed button {}'.format(self.buttons.index(self.sender())+1))
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
QPushButton.clicked
信号发出一个参数,指示按钮的状态。当您连接到lambda插槽时,您分配给idx
的可选参数将被按钮的状态覆盖
相反,将您的连接设置为
button.clicked.connect(lambda state, x=idx: self.button_pushed(x))
这样会忽略按钮状态,并将正确的值传递给方法。小心!只要您将信号连接到一个带有self引用的lambda插槽,您的小部件就不会被垃圾收集!这是因为lambda创建了一个闭包,其中包含对小部件的另一个无法收集的引用
因此,
self.someUIwidget.someSignal.connect(lambda p:self.someMethod(p))
是非常邪恶的:)(显然,创建所有按钮“自动”(在循环中)是很简单的,而不是两个在循环外,两个在循环内,如果这是你的最终目标的话…谢谢你的建议,但是上面的三个菠萝解决方案正是我想要的,并解释了发生了什么。是的,没有理由不在循环中生成所有四个按钮,除了显示一个示例of循环外的行为是如何不同的。我也很高兴了解您的操作方式有什么问题。我花了两天的时间对代码进行注释和取消注释,以发现这就是“漏洞”我正在调查的错误,然后我遇到了您的分析,这正是我最终得出的结论。现在开始更改所有现有代码……(为了记录,如果lambda
将self
传递给某个外部函数,也会出现相同的问题:self.someUIwidget.someSignal.connect(lambda someNonSelfMethod(self))
那么什么是替代方案?@Esostack:取决于您想要实现的目标。如果您只想在插槽中检测发出信号的对象,您可以使用QObject.sender()
方法。此外,您可以将信息存储在小部件属性中,并在插槽函数中访问它们,请参见此示例:@Rhdr ano值得一提的是这里的讨论是“状态”一词的真正用途?@ioaniatr当您连接到单击的信号时,该信号具有所描述的签名。如您所见,当发出信号时,将提供一个包含按钮状态的参数(无论是否选中按钮)。可以根据需要调用代码中的变量,但该变量必须存在,以便Qt不会用选中状态覆盖下一个参数(x=idx
)。