Python&;Tkinter-用于设置标签文本变量问题的按钮命令

Python&;Tkinter-用于设置标签文本变量问题的按钮命令,python,button,lambda,tkinter,Python,Button,Lambda,Tkinter,我正在玩Tkinter,从底部开始构建一个计算器。在我进行过程中,尽可能多地了解活动和图书馆 现在我只想让按钮将按钮上的值传递给顶部的标签 我使用for循环来创建大多数按钮,以避免冗余代码,但现在传递到标签中textvariable的唯一值是我的按钮列表中的最后一项“.”,我不确定这是为什么。有人能帮忙吗 代码如下: from Tkinter import * import Tkinter as tk # main window root = Tk() root.title('Calcul

我正在玩Tkinter,从底部开始构建一个计算器。在我进行过程中,尽可能多地了解活动和图书馆

现在我只想让按钮将按钮上的值传递给顶部的标签

我使用for循环来创建大多数按钮,以避免冗余代码,但现在传递到标签中textvariable的唯一值是我的按钮列表中的最后一项“.”,我不确定这是为什么。有人能帮忙吗

代码如下:

from Tkinter import *
import Tkinter as tk

# main window
root = Tk()
root.title('Calculator')

# button set
buttons = ['1','2','3','4','5','6','7','8','9','0','+','-','/','*','.']

sum_value = StringVar()

# output window
output_window = tk.Label(root, textvariable=sum_value, width=20, height=2).grid(row=0, columnspan=3, sticky=(E,W))

# button creation
r=1
c=0

for i in buttons:
    if c < 2:
        bi = tk.Button(root, text = i, command = lambda: sum_value.set(i), padx = 5, pady = 3).grid(row = r, column = c, sticky = (N,S,E,W))        
        c += 1
    else:
        bi = tk.Button(root, text = i, command = lambda: sum_value.set(i), pady = 3).grid(row = r,column = c,sticky = (N,S,E,W))
        r  += 1
        c = 0

# clear and equals button
clear = tk.Button(root,text='=',padx = 5, pady=3).grid(row=6,column=0,sticky=(N,S,E,W))
clear = tk.Button(root,text='CLEAR',padx = 5, pady=3).grid(row=6,column=1, columnspan = 2,sticky=(N,S,E,W))

root.mainloop()

从Tkinter导入*
将Tkinter作为tk导入
#主窗口
root=Tk()
root.title('计算器')
#按钮组
按钮=['1'、'2'、'3'、'4'、'5'、'6'、'7'、'8'、'9'、'0'、'+'、'-'、'/'、'*'、'.]
sum_value=StringVar()
#输出窗口
输出窗口=tk.Label(根,textvariable=sum\u值,宽度=20,高度=2)。网格(行=0,列span=3,粘性=(E,W))
#按钮创建
r=1
c=0
对于i输入按钮:
如果c<2:
bi=tk.Button(根,text=i,command=lambda:sum_value.set(i),padx=5,pady=3)。网格(行=r,列=c,粘性=(N,S,E,W))
c+=1
其他:
bi=tk.Button(根,text=i,command=lambda:sum_value.set(i),pady=3)。grid(行=r,列=c,粘性=(N,S,E,W))
r+=1
c=0
#清除并等于按钮
clear=tk.Button(根,text='=',padx=5,pady=3).grid(行=6,列=0,粘性=(N,S,E,W))
clear=tk.Button(root,text='clear',padx=5,pady=3).网格(行=6,列=1,列span=2,粘性=(N,S,E,W))
root.mainloop()

这是在循环中声明
lambda
的常见陷阱。变量
i
在调用
lambda
时求值,而不是在定义变量时求值,因此所有函数最终都使用在循环的最终迭代中分配给
i
的值。有一些方法可以解决此问题,例如使用参数并为其指定默认值,该值将在定义函数时进行评估

在您的情况下,您可以将
lambdas
更改为此表单,然后它应该可以工作:

bi = tk.Button(..., command=lambda i=i: sum_value.set(i), ...)
bi.grid(...)
另外请注意,如果执行
bi=Button(…).grid(…)
bi
将被分配
grid
功能的结果,即
None
。无论如何,在这种情况下,您不需要bi,所以这并不重要,但这是另一个常见问题,所以最好不要养成这种习惯。

这个问题很好地解释了您的困境

有两种解决方法:

(1) 默认参数方法如上所述

(2) 每次创建lambda时创建新作用域:

for i in buttons:
    if c < 2:
        bi = tk.Button(root, text = i, command = (lambda a: lambda : sum_value.set(a))(i), padx = 5, pady = 3).grid(row = r, column = c, sticky = (N,S,E,W))        
        c += 1
    else:
        bi = tk.Button(root, text = i, command = (lambda a: lambda : sum_value.set(a))(i), pady = 3).grid(row = r,column = c,sticky = (N,S,E,W))
        r  += 1
        c = 0
使用参数i调用外部lambda函数,该参数为内部lambda函数创建闭包。闭包是记住封闭范围中的值的对象。
内部lambda函数将可以访问
i
在声明lambda函数时拥有的值

@SDilmac如果它也为OP而运行,他/她不会问这个问题,你不觉得吗?@tobias_k太好了!谢谢你,传奇人物!bi是我之前尝试过的东西的剩余部分,打算去掉:-P..@daanstera您可以做的另一件事是将
事件与对设置标签文本的函数的调用绑定。调用的此函数需要为事件对象指定一个参数,通过此参数(它将指向事件对象),您可以访问发生事件的小部件(因此,在您的情况下,它的属性是按钮的文本),然后相应地修改标签。如果我所说的一切对你来说都很奇怪,那么现在就忽略它吧,但是你可能需要理解“事件和绑定”的概念
(lambda a: lambda : sum_value.set(a))(i)