使用lambda表达式连接pyq中的插槽

2024-05-03 13:28:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图将插槽与lambda函数连接起来,但它的工作方式与我预期的不同。在下面的代码中,我成功地连接了前两个按钮。对于第二个,我在一个循环中连接,这是错误的。在我之前的人有同样的问题(Qt - Connect slot with argument using lambda),但这个解决方案对我不起作用。我盯着屏幕看了半个小时,但我不知道我的代码有什么不同。

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函数在信号激发时是否求值?


Tags: lambda函数selfmainconnectbutton按钮layout
3条回答

QPushButton.clicked信号发出一个参数,指示按钮的状态。当您连接到lambda插槽时,您分配给idx的可选参数将被按钮的状态覆盖。

相反,将您的连接设为

button.clicked.connect(lambda state, x=idx: self.button_pushed(x))

这样就会忽略按钮状态,并将正确的值传递给方法。

我也不确定你在这里使用lambda有什么问题。我认为这是因为idx(设置自动按钮时的循环索引)超出了范围,不再包含正确的值。

但我认为你不需要这样做。看起来您使用lambda的唯一原因是可以将参数传递给button_pushed(),从而确定它是哪个按钮。有一个函数sender()可以在button_pushed()插槽中调用,它标识哪个按钮发出了信号。

这里有一个例子,我认为它或多或少地符合你的目的:

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_())

当心!一旦你将你的信号连接到一个lambda插槽并引用self,你的小部件就不会被垃圾收集!这是因为lambda创建了一个闭包,其中包含对小部件的另一个无法收集的引用。

因此,self.someUIwidget.someSignal.connect(lambda p:self.someMethod(p))非常邪恶:)

相关问题 更多 >