【问题标题】:Tkinter Button Commands in For Loop [duplicate]For循环中的Tkinter按钮命令[重复]
【发布时间】:2024-04-19 12:50:01
【问题描述】:

我正在将 python 3 与 tkinter 一起使用,但我遇到了我想从按钮执行的命令的问题。生成了可变数量的按钮,每个访问者一个,我试图从按钮按下调用函数signOut,同时将列表中的相关项目(访问者)传递给它。

我意识到问题在于 for 循环,因为当按下按钮时,i== 列表中的最后一项。我怎样才能使它具体到实际的访客。我似乎无法想到解决方案。任何建议表示赞赏。

buttonDictionary = {}
for i in range(0,len(currentVisitors)):
    buttonDictionary[i] = Button(bottomFrame, text=currentVisitors[i], command=lambda: signOut(topFrame, bottomFrame, currentVisitors[i]))
    buttonDictionary[i].pack()

【问题讨论】:

    标签: python-3.x tkinter


    【解决方案1】:

    据我了解,例如i in a lambda in a lambda in a loop like this is指向变量i本身,而不是每次迭代时变量的值,因此当调用command回调时,它将使用的值i 在那一刻,您注意到这是最后一次迭代的值。

    解决此问题的一种方法是使用partialpartial 实际上会将参数“冻结”在循环中的当前状态,并在调用回调时使用这些参数。

    尝试使用partial 而不是lambda,如下所示:

    from functools import partial
    
    buttonDictionary = {}
    for i in range(0,len(currentVisitors)):
        buttonDictionary[i] = Button(bottomFrame, text=currentVisitors[i], command=partial(signOut, topFrame, bottomFrame, currentVisitors[i]))
        buttonDictionary[i].pack()
    

    另一种我见过但没有尝试过的方法是每次都将i 分配给lambda 中的一个新变量:

    command=lambda i=i: signOut(topFrame, bottomFrame, currentVisitors[i])
    

    当我第一次开始使用 Python 在循环中使用 lambda 时,我已经不止一次被烧坏了(包括一个非常相似的情况,试图为循环中动态生成的按钮分配回调)。我什至创建了一个 sn-p,每当我输入 lambda 时,它都会扩展为 think_about_it('are you sure you want to use a lambda?'),只是为了提醒我这样做给自己带来的痛苦......

    【讨论】:

    • 确实解决了问题。非常感谢您的回复!
    • @user3931640 很高兴它成功了!我被这个烧了好几次了。最糟糕的是当你没有注意到它正在发生时。我会尝试更新我的答案,解释一下为什么会发生这种情况,或者至少链接到可以很好解释的人。