在 pyqt 中使用 lambda 表达式连接插槽
- 2024-12-30 08:41:00
- admin 原创
- 41
问题描述:
我正在尝试使用 lambda 函数连接插槽,但它没有按我预期的方式工作。在下面的代码中,我成功正确连接了前两个按钮。对于我循环连接的后两个按钮,这出错了。在我之前有人有同样的问题(Qt - 使用 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”的结果,按下另外两个按钮都会产生“按下按钮 False”的结果,尽管我预期的是 3 和 4。
我还没有完全理解 lambda 机制。到底连接了什么?指向 lambda 生成的函数的指针(替换了参数)还是每当信号触发时都会评估 lambda 函数?
解决方案 1:
信号QPushButton.clicked
发出一个参数,指示按钮的状态。当您连接到 lambda 槽时,您指定的可选参数idx
将被按钮的状态覆盖。
相反,请按照以下方式建立连接:
button.clicked.connect(lambda state, x=idx: self.button_pushed(x))
这样,按钮状态就会被忽略,正确的值会传递给您的方法。
解决方案 2:
注意!只要您将信号连接到带有自身引用的 lambda 槽,您的小部件就不会被垃圾回收!这是因为 lambda 创建了一个闭包,其中包含对小部件的另一个不可回收的引用。
因此,self.someUIwidget.someSignal.connect(lambda p: self.someMethod(p))
非常邪恶:)
解决方案 3:
说实话,我也不确定你在这里使用 lambda 有什么问题。我认为这是因为 idx(设置自动按钮时的循环索引)超出了范围,不再包含正确的值。
但我认为你不需要这样做。看起来你使用 lambda 的唯一原因是你可以将参数传递给 button_pushed(),以识别它是哪个按钮。在 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_())
解决方案 4:
这很简单。检查工作代码和不工作代码。您有语法错误。
工作代码:
self.button_1.clicked.connect(lambda x:self.button_pushed(1))
不起作用:
button.clicked.connect(lambda x=idx: self.button_pushed(x))
使固定:
button.clicked.connect(lambda x: self.button_pushed(idx))
对于 lambda,您正在定义一个“x”函数,并将该函数解释为“self.button_pushed(idx)”,以便将参数与您的函数一起使用,在这种情况下,参数是 (idx)。只需尝试一下,然后让我知道它是否有效。
他遇到的问题是他试图通过 for 循环创建获得不同的输出。不幸的是,它将最后一个值分配给名为 button 的任何变量,因此结果为 4。前两个是有效的,因为它们不是在 for 循环中创建的,而是单独创建的。
按钮变量的名称在工作中是不同的,如 button_1 和 button_2。在 for 循环中创建的所有按钮都将具有名称 button,从而产生相同的功能。
他尝试做的解决方案如下,并且非常有效。
from sys import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
buttons = []
def newWin():
window = QWidget()
window.setWindowTitle("Lambda Loop")
window.setFixedWidth(1000)
window.move(175, 10)
window.setStyleSheet("background: #161219;")
grid = QGridLayout()
return window, grid
def newButton(text :str, margin_left, margin_right, x):
button = QPushButton(text)
button.setCursor(QCursor(Qt.PointingHandCursor))
button.setFixedWidth(485)
button.setStyleSheet(
"*{border: 4px solid '#BC006C';" +
"margin-left: " + str(margin_left) + "px;" +
"margin-right: " + str(margin_right) + "px;" +
"color: 'white';" +
"font-family: 'Comic Sans MS';" +
"font-size: 16px;" +
"border-radius: 25px;" +
"padding: 15px 0px;" +
"margin-top: 20px;}" +
"*:hover {background: '#BC006C'}"
)
def pushed():
val = x
text = QLabel(str(val))
text.setAlignment(Qt.AlignRight)
text.setStyleSheet(
"font-size: 35px;" +
"color: 'white';" +
"padding: 15px 15px 15px 25px;" +
"margin: 50px;" +
"background: '#64A314';" +
"border: 1px solid '#64A314';" +
"border-radius: 0px;"
)
grid.addWidget(text, 1, 0)
button.clicked.connect(pushed)
return button
app = QApplication(argv)
window, grid = newWin()
def frame1(grid):
for each in [3, 4]:
button = newButton('Button {}'.format(each), 150, 150, each)
buttons.append(button)
pass
b_idx = 0
for each in buttons:
grid.addWidget(each, 0, b_idx, 1, 2)
b_idx += 1
frame1(grid)
window.setLayout(grid)
window.show()
exit(app.exec())
我把所有内容都放在一个地方,这样所有人都能看到。说出你想要做什么比猜测更容易。(你也可以在 Frame 函数的列表中添加新变量,它会为你创建更多具有不同值和功能的按钮。)
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理必备:盘点2024年13款好用的项目管理软件