在 PyQT5 的声明时设置事件的参数值?

Setting event's parameter value at declaration time in PyQT5?

背景

我正在用 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 变量,它们不是在创建时评估,而是在点击时评估。因此,如果用户在 clicked() 方法内部单击第 0 行的 QLabelArow 将具有最后的 row 值(即 QGridLayout) 而不是定义时的那个。如果 self.grid 有 5 行,则用户点击的位置无关紧要,row 的值始终为 5。

我尝试通过定义一个包含 row 值的列表来解决此限制,但它没有任何区别,因为它仍然依赖于单击时的 row 值。

问题

有没有办法使它按预期工作并在创建时而不是在单击时将传递给 click() 方法的值赋值?也欢迎任何不同的方法或方式来实现这一目标。

您的 lambda x: 语句非常接近解决方案,您只是缺少一小部分

使用 Lambdas 存储瞬态值

由于你的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