我正在PyQT5中编写一个简单的应用程序。主QWidget
是QGridLayout
,在视觉上结果应该是这样的:
+-----------------------------------+
row1 | QLabelA | QLabelB | QLabelC |
+-----------------------------------+
row2 | QLabelA | QLabelB | QLabelC |
+-----------------------------------+
row3 | QLabelA | QLabelB | QLabelC |
+-----------------------------------+
...
使用循环填充此QGridLayout
,每次迭代代表一行,所以我有这样的东西:
row = 0
self.grid = QGridLayout()
while row < 10:
filepath = 'icon.png'
icon = QImage(filepath)
QLabelA = QLabel()
QLabelA.setPixmap(QPixmap.fromImage(icon))
QLabelB = QLabel()
QLabelB.setPixmap(QPixmap.fromImage(icon))
QLabelC = QLabel()
QLabelC.setPixmap(QPixmap.fromImage(icon))
self.grid.addWidget(QLabelA, row, 0)
self.grid.addWidget(QLabelB, row, 1)
self.grid.addWidget(QLabelC, row, 2)
row += 1
到目前为止,这很有效。
我的目标是使这些QLabel
中的每一个(视觉上都是图像)都有一个相关的动作,应该在用户对每个动作进行简单点击后触发。为此,我发现a property允许在点击一个对象后调用一个方法,所以我可以这样做:
QLabelA.mousePressedEvent = this.do_something
def do_something(self, event):
...
第一个问题很容易看出:我需要一种方法来识别哪个QLabel
已被点击(即哪一行)。为此,我找到了一种向mousePressedEvent
添加自定义参数的方法。让我们关注QLabelA
字段,这些字段将在点击时调用clicked()
方法:
QLabelA.mousePressEvent = lambda x: self.clicked(row)
def clicked(self, row):
print row
以下是一个大问题:这些QLabelA
字段中的每一个都依赖于row
变量,并且在创建时不会对它们进行评估,而是在点击时进行评估。因此,如果用户点击第0行的QLabelA
,clicked()
方法内,row
将具有最后row
值(即{的行数{1}})而不是定义时的那个。如果QGridLayout
有5行,则用户点击的位置无关紧要,self.grid
的值始终为5.
我尝试通过定义内部带有row
值的列表来解决此限制,但它没有任何区别,因为它仍然依赖于点击时的row
值。
有没有办法让这项工作按预期工作,并在创建时分配传递给row
方法的值而不是点击时间?任何不同的方法或方法也是受欢迎的。
答案 0 :(得分:1)
你很接近使用lambda x:语句的解决方案,你只是缺少一个小块
由于您的row
变量发生了很大变化,因此您需要在创建函数时存储该值;正如您自己注意到的那样,您的self.clicked
引用了当前的row
。为了帮助你,你可以改变你的lambda:
# current: x is the event, row is looked up when the function is called
lambda x: self.clicked(row)
# New: x is the event, r is frozen when the function is created
lambda x, r=row: self.clicked(r)
这会导致每个lambda在创建时设置一个本地r
,而不是在需要该函数时查找row
。