Why is Button parameter “command” executed when declared?
我的代码是:
1 2 3 4 5 6 7 8 9 10 | from Tkinter import * admin = Tk() def button(an): print an print 'het' b = Button(admin, text='as', command=button('hey')) b.pack() mainloop() |
按钮不工作,它在没有我的命令的情况下打印一次"嘿"和"het",然后,当我按下按钮时,什么都没有发生。
若要传递引用,必须仅使用名称,而不使用括号或参数。例如:
1 | b = Button(... command = button) |
如果要传递参数(如"hey"),必须使用一些额外代码:
- 您可以创建一个中间函数,该函数可以在不使用参数的情况下调用,然后调用您的
button 函数, - 您可以使用
lambda 创建所谓的匿名函数。从各个方面来说,它都是一个函数,只是没有名称。当调用lambda 命令时,它返回对所创建函数的引用,这意味着它可以用于按钮的command 选项的值。 - 可以使用functools.partial
对我来说,
要创建一个lambda函数,用一个参数调用您的
1 | lambda: button('hey') |
最终得到的函数在功能上等同于:
1 2 | def some_name(): button('hey') |
正如我前面所说,
1 | b = Button(... command = lambda: button('hey')) |
这个网站上有一个问题,对lambda有很多有趣的评论。看到为什么Python lambda有用的问题了吗?。同样的讨论也有一个答案,说明当需要将变量传入回调时,如何在循环中使用lambda。
最后,请参阅effbot.org上名为tkinter callbacks的部分,了解一个不错的教程。lambda的覆盖率相当低,但是那里的信息可能仍然有用。
您需要创建一个不带参数的函数,可以将其用作命令:
1 | b = Button(admin, text='as', command=lambda: button('hey')) |
请参阅本文档的"将参数传递给回调"部分。
示例图形用户界面:
假设我有图形用户界面:
1 2 3 4 5 6 7 8 | import tkinter as tk root = tk.Tk() btn = tk.Button(root, text="Press") btn.pack() root.mainloop() |
按下按钮会发生什么
请注意,当按下
1 2 3 | def button_press_handle(callback=None): if callback: callback() # Where exactly the method assigned to btn['command'] is being callled |
用:
1 | button_press_handle(btn['command']) |
您可以简单地认为,
没有参数
因此,如果我想在按下按钮时输入1〔5〕的内容,我需要设置:
1 | btn['command'] = print # default to print is new line |
注意
带参数
现在,如果我还想向按下按钮时要调用的方法传递参数,我可以使用匿名函数(可以用lambda语句创建),在本例中,对于
1 | btn['command'] = lambda arg1="Hello", arg2="", arg3="World!" : print(arg1 + arg2 + arg3) |
按下按钮时调用多个方法
没有参数
您也可以使用
1 2 3 | def multiple_methods(): print("Vicariously") # the first inner callback print("I") # another inner callback |
带参数
为了将参数传递给调用其他方法的方法,再次使用
1 2 3 | def multiple_methods(*args, **kwargs): print(args[0]) # the first inner callback print(kwargs['opt1']) # another inner callback |
然后设置:
1 | btn['command'] = lambda arg="live", kw="as the" : a_new_method(arg, opt1=kw) |
从回调返回对象
还需要注意的是,
下面的示例将调用每次按下按钮时更改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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() |
镜子
当在"…"行分配值时,引擎将评估函数的结果。命令=…
"command"期望返回一个函数,这就是为什么使用lambda可以完成此任务,因为它正在创建一个异常的函数,该函数在计算期间返回给"command"。你也可以编写自己的函数代码,它也可以完成任务。
这是一个使用lambda和不使用lambda的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | #!/usr/bin/python # coding=utf-8 from Tkinter import * # Creation de la fenêtre principale (main window) Mafenetre = Tk() res1 = StringVar() res2 = StringVar() def isValidInput(obj): if hasattr(obj, 'get') and callable(getattr(obj, 'get')): return TRUE return FALSE # stupid action 2 (return 12 on purpose to show potential mistake) def action1(*arguments): print"action1 running" for arg in arguments: if isValidInput(arg): print"input value:", arg.get() res1.set(arg.get()) else: print"other value:", arg print" " return 12 # stupid action 2 def action2(*arguments): print"action2 running" a = arguments[0] b = arguments[1] if isValidInput(a) and isValidInput(b): c = a.get() + b.get() res2.set(c) print c print" " # a stupid workflow manager ordered by name def start_tasks(*arguments, **keywords): keys = sorted(keywords.keys()) for kw in keys: print kw,"plugged" keywords[kw](*arguments) # valid callback wrapper with lambda def action1_callback(my_input): return lambda args=[my_input]: action1(*args) # valid callback wrapper without lambda def action1_callback_nolambda(*args, **kw): def anon(): action1(*args) return anon # first input string input1 = StringVar() input1.set("delete me...") f1 = Entry(Mafenetre, textvariable=input1, bg='bisque', fg='maroon') f1.focus_set() f1.pack(fill="both", expand="yes", padx="5", pady=5) # failed callback because the action1 function is evaluated, it will return 12. # in this case the button won't work at all, because the assignement expect a function # in order to have the button command to execute something ba1 = Button(Mafenetre) ba1['text'] ="show input 1 (ko)" ba1['command'] = action1(input1) ba1.pack(fill="both", expand="yes", padx="5", pady=5) # working button using a wrapper ba3 = Button(Mafenetre) ba3['text'] ="show input 1 (ok)" # without a lambda it is also working if the assignment is a function #ba1['command'] = action1_callback_nolambda(input1) ba3['command'] = action1_callback(input1) ba3.pack(fill="both", expand="yes", padx="5", pady=5) # display result label Label1 = Label(Mafenetre, text="Action 1 result:") Label1.pack(fill="both", expand="yes", padx="5", pady=5) # display result value resl1 = Label(Mafenetre, textvariable=res1) resl1.pack(fill="both", expand="yes", padx="5", pady=5) # second input string input2 = StringVar() f2 = Entry(Mafenetre, textvariable=input2, bg='bisque', fg='maroon') f2.focus_set() f2.pack(fill="both", expand="yes", padx="5", pady=5) # third test without wrapper, but making sure that several arguments are well handled by a lambda function ba2 = Button(Mafenetre) ba2['text'] ="execute action 2" ba2['command'] = lambda args=[input1, input2], action=action2: start_tasks(*args, do=action) ba2.pack(fill="both", expand="yes", padx="5", pady=5) # display result label Label2 = Label(Mafenetre, text="Action 2 result:") Label2.pack(fill="both", expand="yes", padx="5", pady=5) # display result value resl2 = Label(Mafenetre, textvariable=res2) resl2.pack(fill="both", expand="yes", padx="5", pady=5) Mafenetre.mainloop() |
这是我的解决方案:
1 2 3 4 5 6 7 8 9 10 11 | from tkinter import * admin = Tk() def button(an): print(an) print("het") def param(): button("hey") button1 = Button(admin, text ="press", command = param) button1.pack() |
基本上,我们要做的是用参数定义函数,然后在没有参数的函数中调用它。
不要使用任何关键字或参数作为函数的输入或括号。这是一个非常简单的解决方案。