按循环使用按钮调用多个函数

时间:2014-10-24 17:33:50

标签: python python-2.7 tkinter

我正在尝试在Python(Tkinter)中运行一个(GUI)程序,该程序应该如下工作:

一个循环生成五个(或者通常是n,我只是尝试为n = 5现在这样做)按钮,然后点击第i个按钮打印出来。这是我做的:

def func(i):
    print i
for i in range(5):
        buttons[i]= Button(but, text= "%s" %str(inputs[i]), command= lambda: func(i+1))
        buttons[i].grid(row= i+2, column= 0)

问题是,点击所有按钮打印5,所以不知何故func(5)被分配给所有按钮。令人惊讶的是,做了以下工作。

buttons[0].config(command= lambda: func(1))
buttons[1].config(command= lambda: func(2)) 
buttons[2].config(command= lambda: func(3))
buttons[3].config(command= lambda: func(4))
buttons[4].config(command= lambda: func(5))

由于我正在尝试对任意数量的输入执行此操作,因此没有其他方法可以在没有循环的情况下执行此操作。有谁可以帮我解决这个问题?谢谢!

2 个答案:

答案 0 :(得分:2)

与许多其他人一样,你已成为lambda illusion的受害者。即使您正在创建5个函数对象,它们都是相同的,因为所有5个函数对象都具有相同的主体,并且在调用任何函数之前不会评估正文中的名称“i”。您的代码等同于

def func(j):
    print j
def cmd():
    func(i+1)
for i in range(5):
        buttons[i] = Button(but, text="%s" % str(inputs[i]), command=cmd)
        buttons[i].grid(row= i+2, column= 0)

很明显,您将相同的命令附加到每个按钮,按任意按钮将使用i的最终值,即4.要获得5个不同的函数,请删除{ {1}}并将def cmd替换为以下任一项:

command=cmd

我强烈建议在不同的函数中使用不同的参数名,尤其不要重复使用循环变量名作为循环中定义的函数的参数名。在3.x中,您可以删除func并使用

command=lambda j=i: func(j+1)
command=lambda j=i+1: func(j)

答案 1 :(得分:1)

问题是可变范围之一。变量i在这里是你的全局范围,因此lambdas都使用同一个变量,它具有按下按钮时的值(即5)。

最简单的解决方法是用lambda j=i+1: func(j)替换你的lambda。

这声明了一个新变量(j),它仅在值的范围内定义,并在声明lambda时赋予i + 1的值。