在循环中生成 ttk 复选框并传递参数的问题 [英] Issue with generating ttk checkboxes in loops and passing arguments

查看:27
本文介绍了在循环中生成 ttk 复选框并传递参数的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试生成可变数量的复选框,并为命令调用函数传入一组唯一的参数.目前所有的复选框在点击时只传递最后生成的复选框的属性(见下面的代码).您愿意提供的任何帮助或建议都会很棒.谢谢!

I am trying to generate a variable number of checkboxes and pass in a unique set of arguments for the command call function. At present all checkboxes when clicked only pass on the attributes of the last generated checkbox(see code below). Any help or suggestions you would be willing to offer would be wonderful. Thanks!

from Tkinter import *
import tkMessageBox
import ttk

root = Tk()

checkData = []
conditionID = []
def onCheck(conditionID,checkData):
    print checkData.get()
    print conditionID

for i in range(0,10): 
     checkData.append(BooleanVar())
     conditionID.append(i)
     l = ttk.Checkbutton(root, text ="",variable=checkData[i],command=lambda: onCheck(conditionID[i],checkData[i]), onvalue=True, offvalue=False)
     w=Message(root,background='ivory',text="test" + str(i),width=60)
     l.grid(column=1,row=i+1)
     w.grid(column=2,row=i+1)

root.mainloop()

推荐答案

这是python中的一个常见问题,与tkinter没有直接关系:

This is a common problem in python and it is not directly related to tkinter:

让我们看看这段代码:

i = 0

def foo():
    # here i will be lookup in the global namespace *when foo will be executed*
    print i

foo() # => 0
i = 1
foo() # => 1

# if we want to force the "evaluation" of i at function definition,
# we have to put it in the function definition
def bar(i=i):
    # here i is the function argument, and it default value is the value of the "global i" at the time the function was defined
    print i

bar() # => 1
i=2
bar() # => 1
foo() # => 2

在您的情况下,这是相同的问题,但使用 lambda(并且 lambdas 是函数)lambda 中i"的评估是在执行 lambda 时进行的(当创建所有复选按钮且 i==9 时)

In your case, this is the same problem but with lambda (and lambdas are functions) The evaluation of "i" in the lambda is made when at the execution of the lambda (when all checkbuttons are created and i==9)

所以你必须这样定义你的命令参数:

So you have to define your command argument this way:

l = ttk.Checkbutton(root, text ="",variable=checkData[i],command=lambda i=i: onCheck(conditionID[i],checkData[i]), onvalue=True, offvalue=False)

或者如果你想更明确:

l = ttk.Checkbutton(root, text ="",variable=checkData[i],command=lambda index=i: onCheck(conditionID[index],checkData[index]), onvalue=True, offvalue=False)

或更多:

for i in range(0,10): 
    checkData.append(BooleanVar())
    conditionID.append(i)
    # we define a new function (10 times)
    # i is resolve at function definition (now)
    def call_onCheck(index=i):
        # the arguments of onCheck are resolved at function execution.
        # it will take what is in the lists at the execution time.
        # it may change or not (in your case : not)
        return onCheck(conditionID[index], checkData[index])
    l = ttk.Checkbutton(root, text ="",variable=checkData[i],command=call_onCheck, onvalue=True, offvalue=False)
    w=Message(root,background='ivory',text="test" + str(i),width=60)
    l.grid(column=1,row=i+1)
    w.grid(column=2,row=i+1)

由于列表的内容不会改变*(在您提供的代码中),您也可以这样写:

As the content of the lists don't change* (in the code you provide), you could also write:

from Tkinter import *
import tkMessageBox
import ttk

root = Tk()

# Those lists are not strictly necessary, but you may want to check this list from other function, So I keep it
checkData = []
# Here you store i the the i index of the list. I'm pretty sure this list is not necessary
conditionID = []

def onCheck(conditionID,checkData):
    print checkData.get()
    print conditionID

for i in range(0,10): 
    boolVar = BooleanVar()
    checkData.append(boolVar)
    conditionID.append(i)
    l = ttk.Checkbutton(root,
                        text ="",
                        variable=boolVar,
                        # we don't need to add a "resolution step" at execution as the values we will need are already known at lambda definition
                        command=lambda boolVar=boolVar, i=i :  onCheck(i, boolVal)),
                        onvalue=True, offvalue=False)
    w=Message(root,background='ivory',text="test" + str(i),width=60)
    l.grid(column=1,row=i+1)
    w.grid(column=2,row=i+1)

root.mainloop()

* 列表中的 BooleanVar 会改变,但它是同一个 booleanVar 对象,所以从列表的角度来看,值不会改变.

* The BooleanVar's in the list will change but it is the same booleanVar object, so from the list't point of view, values don't change.

这篇关于在循环中生成 ttk 复选框并传递参数的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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