【问题标题】:Passing variable through lambda into functions Tkinter通过 lambda 将变量传递给函数 Tkinter
【发布时间】:2012-07-05 13:54:02
【问题描述】:

我对以下代码的问题是通过 lambda 将“i”(只是一个简单的数字范围,但根据 number_boxes 更改)传递给回调,以便创建每个盒子的单独功能。

我已尝试阅读教程并尝试在我的代码中进行各种操作,但它要么不起作用,要么我收到错误“lambda() 只需要 2 个参数,3 个给定”等。我相信我需要制作 'i'一个列表,但我仍然得到这个特定的错误..

我已经评论了出现问题的代码。我需要返回每个框中的值并覆盖文本。

谢谢。

self.clicked = [] # In my __init__ definition
self.numbers = [StringVar() for i in xrange(self.number_boxes) ]   # Create Stringvar for each box

for i in xrange(self.number_boxes): # For each number, create a box

        self.clicked.append(False) # Not clicked in yet
        self.box.append(Entry(self.frame_table,bg='white',borderwidth=0, width=10, justify="center", textvariable=self.numbers[i], fg='grey')) # Textvariable where I enter a value to get after, need to do for each box (use box[i] but cannot for append)
        self.box[i].grid(row=row_list,column=column+i, sticky='nsew', padx=1, pady=1) 
        self.box[i].insert(0, "Value %g" % float(i+1))
        self.box[i].bind("<Button-1>", lambda event, index=i : self.callback(event, index)) # Need to pass the 'i's' to callback but having lambda difficulties

for i in self.numbers: 
        i.trace('w',lambda index=i: self.numberwritten(index) ) # Need for each box again here

def numberwritten(self, index): # A way of combining numberwritten and callback?
    po = self.box[index].get() # Get the values in each box
    print po

def callback(self, event, index):
        if (self.clicked[index] == False): # When clicked in box, overwrite default text with value and change colour to black, not grey
            self.box[index].delete(0, END)
            self.box[index].config(fg='black')
                self.clicked[index] = True

更新:当前问题:需要将“i”的所有值传递给回调,而不仅仅是一个,而是如何将列表放入 lambda?

错误:

Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python26\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
TypeError: lambda() takes at most 1 argument (3 given)

【问题讨论】:

  • 我不明白po = box[i].get()这行:不应该是po = self.box[i].get()吗?我也不明白lambda i: self.numberwritten(n)n 来自哪里?
  • 是的,对不起,我使用的是旧版本的代码。代码已编辑。
  • 粘贴完整的回溯
  • 我不确定你的意思,我已经包含了所有与 numberwritten 函数相关的内容。
  • 您真正想要完成的是什么?每次更改每个条目时,您真的需要回调吗?出于什么目的?是用于输入验证吗?如果是这样,有更好的方法来对条目小部件进行输入验证。

标签: python class lambda callback tkinter


【解决方案1】:

您的代码非常接近,但是这一行:

self.box[i].bind("<Button-1>", lambda self, event,i : self.callback(event, data))

应该是

self.box[i].bind("<Button-1>", lambda event, index=i: self.callback(event, index))

对象index 只是一个任意标签,我们为其分配i 的值。请注意,如果我们传递i,而不是变量名,Python 会抛出错误。而且我们不需要通过self;它通过在函数调用中的使用隐式传递:self.callback()

我唯一的其他评论是您应该将clicked 变成一个列表,以便您可以跟踪用户选择了哪些对象。您可以完全按照box 的形成方式形成它。祝你好运。


以下是将clicked 转换为列表的一些提示,因为我认为这是您当前遇到的问题。 编辑:根据 J.F. Sebastian 的 cmets 更改了几行。

# Create an empty list based on the number of boxes created 
# above. This could go in your class's __init__ function, 
# or it could be declared globally, depending on the scope
# of self.box and the loop which determines its length.
self.clicked = ([False] * len(self.box))

# Finally, in your callback, check one member of the list,
# depending on which box was clicked.
def cb(self, event, index):
    if not self.clicked[index]:
        self.box[index].delete(0, END)
        self.box[index].config(fg='black')
        self.clicked[index] = True
    # Print the value of each of the widgets stored in the box list.
    for i, j in enumerate(self.box):
        print("%ith element: %s" % (i, j.get()))  

【讨论】:

  • 这项工作,但问题是我的循环,因为索引必须是一个包含 i 的所有值的列表吗?我也不明白如何点击列表,因为它不是数字列表。很抱歉成为这些事情的初学者!
  • Clicked 是 bool 对象,不能使用 append。我正在努力获得回调函数的最终点并通常将我的代码整理出来。
  • 更新了当前的代码。只能将 index=0 传递给回调,并且仍然想知道是否可以合并 numberwritten 和回调以写入和读取框中的值?
  • 关于列表 - 它们可以包含您想要的任何类型,因此只需使用 clicked = [] 创建一个空列表,然后使用 clicked.append(False)
  • 您可以改用:self.clicked = [False] * len(self.box)if not self.clicked[index]: 语法。
【解决方案2】:

更新: 看来您的 lambda 完全是多余的。完全删除它。

尝试:

self.box[i].bind("<Button-1>",self.callback)

代替:

lambda self, event, i: self.callback(event, i)

更新:

当我输入答案时,您似乎使情况恶化了,也许 对 lambda-idiom 的一点澄清会比我的解决方案更有帮助 以上。 ;-)

lambda 函数也称为匿名函数,因为它们不需要 有名字。

比较以下示例:

>>>ulist = 'a1 s3 d2 f4 k6 w9'.split()

def normal_sort(L,R):
    result = int(L[1]) - int(R[1])
    return result

>>> sorted(ulist, normal_sort)
['a1', 'd2', 's3', 'f4', 'k6', 'w9']

与 lambda 函数相同:

sorted(ulist, lambda L, R: int(L[1])-int(R[1]))
['a1', 'd2', 's3', 'f4', 'k6', 'w9']

lambda 函数有

  1. 没有名字
  2. 无参数括号
  3. 没有返回语句,因为它的单个语句的求值被作为返回值传回。

您可以通过为 lambda 函数指定名称来命名它:

lambda_sort = lambda L, R: int(L[1])-int(R[1])

但是切换到正常功能可能已经很有用了。

【讨论】:

  • 这不起作用,它仍然给我一个参数数量错误。
  • 感谢您的更新(我正在使用我发现的示例来尝试使我的代码清晰,显然不是!)。但是它似乎仍然不起作用,这真的让我感到困惑!我已经把我的代码改回来了..!
  • 我不知道 StringVar.trace 应该有哪些和多少个参数,但我的猜测是:一个,这个应该是一个字符串,或者至少可以转换为字符串,因此杀死你的 lambda也在那里建造
  • @DonQuestion:跟踪回调采用 3 个参数:name1name2op。第一个是变量的名称,第二个是变量的索引,如果它是一个数组(我认为 tkinter 不支持),第三个是“read”、“write”或“unset” ,取决于哪个事件导致回调被调用。
  • 啊,好吧——我不是一个生动的 tcl/tk 用户——这整个“一切都是字符串”对我没有吸引力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-18
  • 2015-01-28
相关资源
最近更新 更多