Вопрос-Ответ

How to pass arguments to a Button command in Tkinter?

Как передать аргументы команде 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))
2023-03-26 10:40 python python-3.x tkinter