Как передать аргументы командной кнопки в 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))
Это просто вызывает метод немедленно, и нажатие кнопки ничего не делает.
11 ответов:
Я лично предпочитаю использовать
lambdasв таком сценарии, потому что imo это яснее и проще, а также не заставляет вас писать много методов обертки, если у вас нет контроля над вызываемым методом, но это, безусловно, вопрос вкуса.вот как вы это сделаете с лямбда (обратите внимание, что в функциональном модуле есть также некоторая реализация карринга, поэтому вы можете использовать и это):
button = Tk.Button(master=frame, text='press', command= lambda: action(someNumber))
Это также можно сделать с помощью
partialиз стандартной библиотеки functools, например:from functools import partial #(...) action_with_arg = partial(action, arg) button = Tk.Button(master=frame, text='press', command=action_with_arg)
способность Python предоставлять значения по умолчанию для аргументов функции дает нам выход.
def fce(x=myX, y=myY): myFunction(x,y) button = Tk.Button(mainWin, text='press', command=fce)см.:http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/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))
пример GUI:
допустим, у меня есть графический интерфейс:
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'])вы можете просто думаю, что должен быть установлен как ссылка на метод, который мы хотим называться, как
callbackinbutton_press_handle.
вызов метода(обратный звонок) при нажатии кнопки
без аргументы
так что если бы я хотел
btn['command'] = print # default to print is new lineобратите пристальное внимание на отсутствие на
()СС
причина, по которой он немедленно вызывает метод и нажатие кнопки ничего не делает, это
action(somenumber)вычисляется и его возвращаемое значение присваивается как команда для кнопки. Так что еслиactionпечатает что-то, чтобы сказать вам, что он работает и возвращаетNone, ты просто бегиactionчтобы оценить его возвращаемое значение и учитываяNoneкак команда для кнопки.есть кнопки для вызова функций с разными аргументами можно использовать глобальные переменные, хотя я не могу рекомендовать это:
import Tkinter as Tk frame = Tk.Frame(width=5, height=2, bd=1, relief=Tk.SUNKEN) frame.grid(row=2,column=2) frame.pack(fill=Tk.X, padx=5, pady=5) def action(): global output global variable output.insert(Tk.END,variable.get()) button = Tk.Button(master=frame, text='press', command=action) button.pack() variable = Tk.Entry(master=frame) variable.pack() output = Tk.Text(master=frame) output.pack() if __name__ == '__main__': Tk.mainloop()то, что я бы сделал, это сделать
classчьи объекты будут содержать все необходимые переменные и методы для их изменения по мере необходимости:import Tkinter as Tk class Window: def __init__(self): self.frame = Tk.Frame(width=5, height=2, bd=1, relief=Tk.SUNKEN) self.frame.grid(row=2,column=2) self.frame.pack(fill=Tk.X, padx=5, pady=5) self.button = Tk.Button(master=self.frame, text='press', command=self.action) self.button.pack() self.variable = Tk.Entry(master=self.frame) self.variable.pack() self.output = Tk.Text(master=self.frame) self.output.pack() def action(self): self.output.insert(Tk.END,self.variable.get()) if __name__ == '__main__': window = Window() Tk.mainloop()
один простой способ-настроить
buttonСlambdaкак следующий синтаксис:button['command'] = lambda arg1 = local_var1, arg2 = local_var2 : function(arg1, arg2)
button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))Я считаю, что это должно исправить
используйте лямбду для передачи входных данных в командную функцию, если у вас есть больше действий для выполнения, например (я пытался сделать его универсальным, поэтому просто адаптируйте):
event1 = Entry(master) button1 = Button(master, text="OK", command=lambda: test_event(event1.get())) def test_event(event_text): if not event_text: print("Nothing entered") else: print(str(event_text)) # do stuffэто передаст информацию в случае к функции кнопки. Может быть, есть более Питонские способы написать это, но это работает для меня.
JasonPy-несколько вещей...
Если вы вставляете кнопку в петлю, она будет создаваться снова и снова... что, вероятно, не то, что вы хотите. (может это)...
причина, по которой он всегда получает последний индекс, - это лямбда-события, запускаемые при их нажатии, а не при запуске программы. Я не уверен на 100%, что вы делаете, но, возможно, попробуйте сохранить значение, когда оно будет сделано, а затем вызвать его позже с помощью кнопки лямбда.
например: (не используйте этот код, просто пример)
for entry in stuff_that_is_happening: value_store[entry] = stuff_that_is_happeningзатем вы можете сказать....
button... command: lambda: value_store[1]надеюсь, что это помогает!
для потомков: вы также можете использовать классы для достижения чего-то подобного. Например:
class Function_Wrapper(): def __init__(self, x, y, z): self.x, self.y, self.z = x, y, z def func(self): return self.x + self.y + self.z # execute functionкнопка может быть просто создана:
instance1 = Function_Wrapper(x, y, z) button1 = Button(master, text = "press", command = instance1.func)этот подход также позволяет изменить аргументы функции, т. е. параметр
instance1.x = 3.
основываясь на ответе Мэтта Томпсона: класс можно сделать вызываемым, чтобы его можно было использовать вместо функции:
import tkinter as tk class Callback: def __init__(self, func, *args, **kwargs): self.func = func self.args = args self.kwargs = kwargs def __call__(self): self.func(*self.args, **self.kwargs) def default_callback(t): print("Button '{}' pressed.".format(t)) root = tk.Tk() buttons = ["A", "B", "C"] for i, b in enumerate(buttons): tk.Button(root, text=b, command=Callback(default_callback, b)).grid(row=i, column=0) tk.mainloop()
Comments