如何在Tkinter中为按钮命令传递参数?
假设我用Python的Tkinter库做了一个按钮,代码如下:
import Tkinter as Tk
win = Tk.Toplevel()
frame = Tk.Frame(master=win).grid(row=1, column=1)
button = Tk.Button(master=frame, text='press', command=action)
当我按下这个按钮时,会调用一个叫做 action
的方法。但是如果我想在调用这个方法的时候传一些参数,该怎么办呢?
我尝试了下面的代码:
button = Tk.Button(master=frame, text='press', command=action(someNumber))
但是这样做会立刻调用这个方法,按下按钮却没有任何反应。
想了解更多标准的解决方法(不是专门针对Tkinter的),可以查看 Python 参数绑定。在Tkinter(或其他图形界面框架)中使用回调函数时,有一些特别的注意事项,因为回调函数的返回值是没用的。
如果你在一个循环中创建多个按钮,并且根据循环计数器给每个按钮传递不同的参数,可能会遇到问题,这种情况被称为 晚绑定。详细信息可以查看 在for循环中创建按钮并传递命令参数。
14 个回答
示例图形界面:
假设我有一个这样的图形界面:
import tkinter as tk
root = tk.Tk()
btn = tk.Button(root, text="Press")
btn.pack()
root.mainloop()
按钮被按下时发生了什么
你会看到,当 btn
被按下时,它会调用 它自己的 函数,这个函数和下面例子中的 button_press_handle
很相似:
def button_press_handle(callback=None):
if callback:
callback() # Where exactly the method assigned to btn['command'] is being callled
具体来说:
button_press_handle(btn['command'])
你可以简单理解为 command
选项应该设置为我们想要调用的方法的引用,这和 button_press_handle
中的 callback
类似。
按钮被按下时调用方法(回调)
没有 参数
所以如果我想在按钮被按下时 print
一些东西,我需要设置:
btn['command'] = print # default to print is new line
请注意 print
方法后面没有 ()
,这意味着:"这是我希望你在按下时调用的方法的名字 但是 不要立刻调用它。" 但是,我没有传递任何参数给 print
,所以它会打印出在没有参数时的默认内容。
有 参数
现在如果我想在按钮被按下时传递参数给 我想要调用的方法,我可以使用匿名函数,这可以通过 lambda 语句来创建,像下面这样使用 print
内置方法:
btn['command'] = lambda arg1="Hello", arg2=" ", arg3="World!" : print(arg1 + arg2 + arg3)
按钮被按下时调用 多个 方法
没有 参数
你也可以使用 lambda
语句来实现这个功能,但这被认为是不好的实践,所以我这里不包括。好的做法是定义一个单独的方法 multiple_methods
,这个方法会调用你想要的其他方法,然后将它设置为按钮按下时的回调:
def multiple_methods():
print("Vicariously") # the first inner callback
print("I") # another inner callback
有 参数
为了向调用其他方法的方法传递参数,再次使用 lambda
语句,但首先:
def multiple_methods(*args, **kwargs):
print(args[0]) # the first inner callback
print(kwargs['opt1']) # another inner callback
然后设置:
btn['command'] = lambda arg="live", kw="as the" : a_new_method(arg, opt1=kw)
从回调返回对象
另外要注意的是,callback
不能真正 return
,因为它只是在 button_press_handle
内部被调用,像 callback()
这样,而不是 return callback()
。它确实会 return
,但 不 在那个函数外部。因此,你应该 修改 当前作用域内可以访问的对象。
完整示例与 全局 对象修改
下面的例子会在每次按钮被按下时调用一个方法,改变 btn
的文本:
import tkinter as tk
i = 0
def text_mod():
global i, btn # btn can be omitted but not sure if should be
txt = ("Vicariously", "I", "live", "as", "the", "whole", "world", "dies")
btn['text'] = txt[i] # the global object that is modified
i = (i + 1) % len(txt) # another global object that gets modified
root = tk.Tk()
btn = tk.Button(root, text="My Button")
btn['command'] = text_mod
btn.pack(fill='both', expand=True)
root.mainloop()
这也可以通过使用标准库中的 partial
来实现,具体可以参考 functools,用法如下:
from functools import partial
#(...)
action_with_arg = partial(action, arg)
button = Tk.Button(master=frame, text='press', command=action_with_arg)
这可以通过使用一个 lambda
来实现,像这样:
button = Tk.Button(master=frame, text='press', command= lambda: action(someNumber))
这是一种简单的方法,可以在不需要额外包装方法或修改原始 action
的情况下,绑定参数。