Python:Tkinter菜单项未传递正确值

3 投票
1 回答
854 浏览
提问于 2025-04-17 03:01

我现在正在为我的应用程序制作一个图形用户界面(使用Tkinter)。我遇到了一些问题,就是想创建几个下拉菜单来选择日期。我的应用程序可以生成带标签的菜单,但是无论我点击哪个按钮,最后一个菜单的值总是被传递给tkinter的可变IntVar。

下面是我代码的一部分,突出了我的问题。用户点击的年份应该是year,但它总是显示为2011。

from Tkinter import *
import tkFileDialog as dialog
import datetime
import calendar

window = Tk()
text = Text(window)
text.pack()

year = IntVar()
list_of_years = [1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011]

def year_seter(value):
  year.set(value)

menubar = Menu(window)
yearmenu = Menu(menubar)
for the_year in list_of_years:
  yearmenu.add_command(label=str(the_year), command=lambda : year_seter(the_year))
menubar.add_cascade(label = 'Year', menu=yearmenu)
window.config(menu=menubar)

label = Label(window, textvariable=year)
label.pack()
window.mainloop()

有人能告诉我,为什么会这样吗?谢谢你们的时间!

1 个回答

4

command 改成:

lambda the_year=the_year: year_seter(the_year)

这个问题和 Python 查找 the_year 的值有关。当你使用

lambda : year_seter(the_year)

the_year 在 lambda 函数的本地范围内找不到,所以 Python 会去更大的范围找,包括全局范围和内置范围。它在全局范围找到了 the_year。这个 for-loop 使用了 the_year,而在 for-loop 结束后,the_year 保留了最后的值,也就是 2011。因为 lambda 函数是在 for-loop 结束后执行的,所以 Python 给 the_year 赋的值是 2011。

相反,如果你使用一个带有默认值的参数,那么这个默认值在函数(lambda)被定义的时候就固定下来了。因此,每个 lambda 都会有一个不同的 the_year 值作为默认值。

现在当调用 lambda 时,Python 又去找 the_year 的值,这次它在 lambda 的本地范围找到了。它把默认值绑定到 the_year 上。


附注:

  1. 你也可以不定义 year_seter,直接这样做:

    lambda the_year=the_year: year.set(the_year)
    
  2. list_of_years = range(1995,2012) 也可以用。

撰写回答