在 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 行的 QLabelA
,row
将具有最后的 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
。
背景
我正在用 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 行的 QLabelA
,row
将具有最后的 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
。