如何在Tkinter中为按钮命令传递参数?

270 投票
14 回答
476166 浏览
提问于 2025-04-16 22:46

假设我用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 个回答

31

示例图形界面:

假设我有一个这样的图形界面:

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()

镜像

155

这也可以通过使用标准库中的 partial 来实现,具体可以参考 functools,用法如下:

from functools import partial
#(...)
action_with_arg = partial(action, arg)
button = Tk.Button(master=frame, text='press', command=action_with_arg)
405

这可以通过使用一个 lambda 来实现,像这样:

button = Tk.Button(master=frame, text='press', command= lambda: action(someNumber))

这是一种简单的方法,可以在不需要额外包装方法或修改原始 action 的情况下,绑定参数。

撰写回答