Как передать аргументы команде Button в Tkinter?
Предположим, у меня есть следующее Button
сделано с помощью Tkinter в Python:
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
вызывается, когда я нажимаю кнопку, но что, если бы я захотел передать некоторые аргументы методу action
?
Я пробовал использовать следующий код:
button = Tk.Button(master=frame, text='press', command=action(someNumber))
Это просто немедленно вызывает метод, и нажатие кнопки ничего не делает.
Смотрите Связыватели аргументов Python для стандартных методов (не специфичных для Tkinter) решения проблемы. Работа с обратными вызовами в Tkinter (или других графических фреймворках) требует некоторых особых соображений, поскольку возвращаемое значение из обратного вызова бесполезно.
Если вы попытаетесь создать несколько кнопок в цикле, передавая каждой разные аргументы на основе счетчика цикла, вы можете столкнуться с проблемами из-за того, что называется поздней привязкой. Пожалуйста, смотрите, tkinter создает кнопки в цикле for, передавая аргументы команды для получения подробной информации.
Переведено автоматически
Ответ 1
Это можно сделать с помощью lambda
, вот так:
button = Tk.Button(master=frame, text='press', command= lambda: action(someNumber))
Это простой способ привязать аргумент без явного метода-оболочки или изменения исходного action
.
Ответ 2
Это также можно сделать, используя partial
из стандартной библиотеки functools, например:
from functools import partial
#(...)
action_with_arg = partial(action, arg)
button = Tk.Button(master=frame, text='press', command=action_with_arg)
Ответ 3
Пример графического интерфейса:
Допустим, у меня есть графический интерфейс:
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
параметр должен быть установлен как, ссылка на метод, который мы хотим вызвать, аналогично callback
в button_press_handle
.
Вызов метода (обратный вызов) При нажатии кнопки
Без аргументов
Итак, если бы я хотел print
что-то делать при нажатии кнопки, мне нужно было бы установить:
btn['command'] = print # default to print is new line
Обратите пристальное внимание на отсутствие метода ()
with 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
with 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()
Ответ 4
Способность Python предоставлять значения по умолчанию для аргументов функции дает нам выход.
def fce(x=myX, y=myY):
myFunction(x,y)
button = Tk.Button(mainWin, text='press', command=fce)
Смотрите: https://tkdocs.com/shipman/extra-args.html
Для получения дополнительных кнопок вы можете создать функцию, которая возвращает функцию:
def fce(myX, myY):
def wrapper(x=myX, y=myY):
pass
pass
pass
return x+y
return wrapper
button1 = Tk.Button(mainWin, text='press 1', command=fce(1,2))
button2 = Tk.Button(mainWin, text='press 2', command=fce(3,4))
button3 = Tk.Button(mainWin, text='press 3', command=fce(9,8))