从字符串列表创建 PyQt 菜单
我有一个字符串列表,想为每个字符串创建一个菜单条目。 当用户单击其中一个条目时,始终应使用字符串作为参数来调用相同的函数。 经过一番尝试和研究,我想出了这样的结果:
import sys
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.menubar = self.menuBar()
menuitems = ["Item 1","Item 2","Item 3"]
menu = self.menubar.addMenu('&Stuff')
for item in menuitems:
entry = menu.addAction(item)
self.connect(entry,QtCore.SIGNAL('triggered()'), lambda: self.doStuff(item))
menu.addAction(entry)
print "init done"
def doStuff(self, item):
print item
app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
现在的问题是每个菜单项都会打印相同的输出:“Item 3”而不是相应的输出。 我很感谢您提供有关如何解决此问题的任何想法。 谢谢。
I have a list of strings and want to create a menu entry for each of those strings. When the user clicks on one of the entries, always the same function shall be called with the string as an argument. After some trying and research I came up with something like this:
import sys
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.menubar = self.menuBar()
menuitems = ["Item 1","Item 2","Item 3"]
menu = self.menubar.addMenu('&Stuff')
for item in menuitems:
entry = menu.addAction(item)
self.connect(entry,QtCore.SIGNAL('triggered()'), lambda: self.doStuff(item))
menu.addAction(entry)
print "init done"
def doStuff(self, item):
print item
app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
Now the problem is that each of the menu items will print the same output: "Item 3" instead of the corresponding one. I'm thankful for any ideas about how I can get this right. Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你遇到了Python中经常提到的(也许不完全迂腐正确;-)作为“范围问题”——绑定很晚(在调用时进行词法查找),而你希望它早点(在定义时间)。 因此,您现在可以
尝试:
这会“预测”绑定,因为默认值(如此处的
item
之一)会在默认时间计算一次。 添加一层函数嵌套(例如双 lambda)也可以,但这里有点矫枉过正!-)您也可以使用
functools.partial(self.doStuff, item)
(带有当然,在顶部导入 functools )这是另一个很好的解决方案,但我想我会选择最简单(也是最常见)的“参数的假默认值”习惯用法。You're meeting what's been often referred to (maybe not entirely pedantically-correctly;-) as the "scoping problem" in Python -- the binding is late (lexical lookup at call-time) while you'd like it early (at def-time). So where you now have:
try instead:
This "anticipates" the binding, since default values (as the
item
one here) get computed once an for all at def-time. Adding one level of function nesting (e.g. a double lambda) works too, but it's a bit of an overkill here!-)You could alternatively use
functools.partial(self.doStuff, item)
(with animport functools
at the top of course) which is another fine solution, but I think I'd go for the simplest (and most common) "fake default-value for argument" idiom.这应该可行,但我很确定有更好的方法,但我现在不记得了。
编辑:
较短的版本,这仍然不是我正在考虑的......或者也许是另一种语言? :)
This should work, but I'm pretty sure there was a better way that I can't recall right now.
Edit:
Shorter version, that still isn't what I'm thinking about... or maybe it was in another language? :)