如何获得由 for 循环生成的 TK 按钮以将输入传递给他们的命令?(Python) [英] How can I get TK buttons, generated by a for loop, to pass input to their command? (Python)

查看:81
本文介绍了如何获得由 for 循环生成的 TK 按钮以将输入传递给他们的命令?(Python)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个动态生成 GUI 的程序.我不知道我会有多少个按钮,如果有的话.

I have a program which dynamically generates a GUI. I don't know how many buttons I will have, if any at all.

具体问题是这样的:

for varname in self.filetextboxes:
    if self.varDict[varname]=='':
        self.varDict[varname] = (StringVar(),)
        self.varDict[varname][0].set('')

    fileButton = Button(self, text=" ", command = lambda:self.varDict[varname][0].set(tkFileDialog.askopenfilename()), image=self.filephoto)

    ftb = Entry(self, textvariable = self.varDict[varname][0],width=40,background='white')

我有一个 for 循环来创建文本框和按钮.StringVar() 存储在字典中,键为 varname.

I have a for loop which creates the textboxes and the buttons. The StringVar() is stored in a dictionary with key varname.

因为我无法在按钮的回调函数中传递参数,所以我在每个按钮中定义了一个 lambda.这将与在此循环中创建的文本框关联的 StringVar() 设置为文件对话框的输出.

because I can't pass arguments in the callback function of the button, I instead define a lambda in each button. This sets the StringVar() associated with the textbox created in this loop to the output of a filedialog box.

问题是,传递给 lambda 的 varname 不是传递值,而是仅传递变量的名称.因此,虽然文本框与它们在 for 循环中创建的变量相关联,但按钮中的 lambda 始终使用 varname 的当前值.

The problem is, the varname passed to the lambda isn't passing the value, but the name of the variable only. So while the textboxes are associated with the variable they were created with in the for loop, lambdas in the buttons uses the current value of varname at all times.

换句话说,每个文本框只链接一个变量,但所有的按钮只设置最终创建的文本框的文本,即最终值为 varname 的文本框.

In other words, each textbox links to only one variable, but all the buttons only set the text of the final textbox created, i.e. the textbox with the final value of varname.

还有其他方法可以解决这个问题吗?我可以让 lambda 以某种方式只使用定义的 varname 值,而不使用 varname 的未来值吗?

Is there another way to approach this? Can I make the lambda somehow only use the value of varname as it is defined, and not use future values of varname?

推荐答案

我不得不承认——这个问题让我有点难受.由于您将 Button 与 Entry 和 stringvar 配对,一种解决方法是将它们包装在一个类中.(我可能会争辩说,无论如何,这更优雅一些......)

I have to admit -- this one has me a little bit stumped. Since you're pairing a Button with an Entry and stringvar, one workaround is to wrap those together in a class. (I could probably argue that this is a little more elegant anyway...)

import Tkinter as tk

class ButtonEntry(tk.Frame):
    def __init__(self,master,ss):
        tk.Frame.__init__(self)
        self.var=tk.StringVar()
        self.var.set(ss)
        self.Button=tk.Button(self,text='Button',command=lambda :self.var.set("foo!"))
        self.Entry=tk.Entry(self,textvariable=self.var)
        self.Button.grid(row=0,column=0)
        self.Entry.grid(row=0,column=1)


class App(tk.Frame):
    def __init__(self,master=None):
        tk.Frame.__init__(self,master)
        self.BEs=[]
        for i in range(10):
            b=ButtonEntry(self,'Button %d'%i)
            b.grid(row=i,column=0)
            self.BEs.append(b)


if __name__ == '__main__':
    root=tk.Tk()
    f=App(root)
    f.grid(row=0,column=0)
    root.mainloop()

然而,我真的很想知道为什么 lambda 的行为方式如此.我确信你所拥有的应该可以工作.

However, I would really love to know why the lambda behaves the way it does. I thought for sure what you had should work.

编辑

我已经追踪了 lambda 函数的行为.https://stackoverflow.com/a/10452819/748858 提供了一个很好的示例,说明如何正确执行此操作.问题是 lambda 函数中的变量仍然绑定到声明 lambda 的作用域.为了将它们与该作用域分离,您需要将它们设置为函数的关键字参数.好的!我今天早上学到了一些新东西.

I've tracked down the behavior of the lambda function. https://stackoverflow.com/a/10452819/748858 gives a great example of how to do this properly. The problem is that the variables in the lambda function are still bound to the scope where the lambda was declared. In order to disassociate them with that scope, you need to set them as a keyword argument to the function. Nice! I learned something new this morning.

这篇关于如何获得由 for 循环生成的 TK 按钮以将输入传递给他们的命令?(Python)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆