通过Tkinter中的按钮将参数传递给函数,循环中的starnge行为 [英] Passing argument to a function via a Button in Tkinter, starnge behaviour in loop
问题描述
我目前正在尝试修复 Python 书籍Python 下一步"中作者尚未修复的错误并在代码中留下评论:稍后修复"
I am currently trying to fix a bug in the python book "Python next step" which the author has not fixed and left a comment in the code : "Fix later"
我的第一个解决方案失败了,但第二个解决方案通过删除循环而成功.问题是我不知道为什么第一个解决方案失败了!
My first solution failed but the second solution succeeded by removing the loop. Problem is I cannot figure out why the first solution fails!
解决方案 1:
当用户使用循环点击 Tkinter 中制作的计算器中的按钮时,Button 对象和名为 click thecalculator 的函数只是从 lambda 参数打印一个大写的 C.代码注释为有问题的鳕鱼附近的人字形,在我所说的点上.
When a user clicks the button in the calculator made in Tkinter using a loop, Button object and a function called click the calculator just prints a capital C from the lambda argument.The code is commented by chevrons near the offending cod, at the points I am talking about.
解决方案 2:
删除生成按钮的循环并重复手动编码每个按钮!这很有效,正如 Brian kernighan 建议的那样:在使其高效之前先让它工作!
Remove the loop that generated buttons and hand code each button repetitively!This works and as Brian kernighan suggest: getting it to work first before making it efficient!
代码:
# myCalculator3_final.py
from Tkinter import *
from decimal import *
# key press function:
def click(key):
display.insert(END, key)
##### main:
window = Tk()
window.title("MyCalculator")
# create top_row frame
top_row = Frame(window)
top_row.grid(row=0, column=0, columnspan=2, sticky=N)
# use Entry widget for an editable display
display = Entry(top_row, width=45, bg="light green")
display.grid()
# create num_pad_frame
num_pad = Frame(window)
num_pad.grid(row=1, column=0, sticky=W)
# This method of passing an argument to click work! Loop removed and buttons hand code
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#-------------------------------------------------------------------------
# create num_pad buttons passing an argument to the command function click
#-------------------------------------------------------------------------
seven = Button(num_pad, text="7", width=5, command=lambda :click("7"))
seven.grid(row=0,column=0)
eight = Button(num_pad, text="8", width=5, command=lambda :click("8"))
eight.grid(row=0,column=1)
nine= Button(num_pad, text="9", width=5, command=lambda :click("9"))
nine.grid(row=0,column=2)
four= Button(num_pad, text="4", width=5, command=lambda :click("4"))
four.grid(row=1,column=0)
five= Button(num_pad, text="5", width=5, command=lambda :click("5"))
five.grid(row=1,column=1)
six= Button(num_pad, text="6", width=5, command=lambda :click("6"))
six.grid(row=1,column=2)
one= Button(num_pad, text="1", width=5, command=lambda :click("1"))
one.grid(row=2,column=0)
two= Button(num_pad, text="2", width=5, command=lambda :click("2"))
two.grid(row=2,column=1)
three= Button(num_pad, text="3", width=5, command=lambda :click("3"))
three.grid(row=2,column=2)
zero= Button(num_pad, text="0", width=5, command=lambda :click("0"))
zero.grid(row=2,column=0)
#---------------------------------------------------------------------------
# calculate the row, column for button
# create operator_frame
operator = Frame(window)
operator.grid(row=1, column=1, sticky=E)
operator_list = [
'*', '/',
'+', '-',
'(', ')',
'C' ]
# The authors code and I have added the same lambda function as above but
#it just prints out capital C
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
r = 0
c = 0
for btn_text in operator_list:
Button(operator, text=btn_text, width=5, command=lambda: click(btn_text)).grid(row=r,column=c)
c = c+1
if c > 1:
c = 0
r = r+1
##### Run mainloop
window.mainloop()
问题:
为什么用于单击传递参数的 lambda 调用方法在循环中不起作用并且只显示一个 C 但如果我删除循环它就可以工作!
Why does the lambda calling method to click passing an argument not work in the loop and only display a C but if I remove the loop it works!
推荐答案
在这一行:
Button(operator, text=btn_text, width=5, command=lambda: click(btn_text)).grid(row=r,column=c)
lambda 中 btn_text
的值不会被其当前值冻结.相反,当 btn_text
在循环的下一次迭代中发生变化时,它在 lambda 中求值的值也会发生变化.这意味着您的所有按钮实际上都有一个 click('C')
命令,因为 'C'
是 btn_text
的最终值.
The value of btn_text
within the lambda will not become frozen with its current value. Instead, when btn_text
changes in the next iteration of the loop, the value it evaluates to in the lambda will also change. This means that all of your Buttons effectively have a click('C')
command, since 'C'
is the final value of btn_text
.
你可以这样做:
command=lambda text=btn_text: click(text)
或
command=(lambda text: lambda: click(text))(btn_text)
text
会捕获btn_text
的当前值,之后不会改变.您的命令将使用正确的参数调用.
text
will capture the current value of btn_text
, and not change afterwards. Your commands will get called with the proper arguments.
这篇关于通过Tkinter中的按钮将参数传递给函数,循环中的starnge行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!