Tkinter에서 Button 명령에 인수를 전달하는 방법은 무엇입니까?


175

Button파이썬에서 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버튼을 누를 때 메소드 가 호출되지만 메소드에 인수를 전달하려면 어떻게해야 action합니까?

다음 코드로 시도했습니다.

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

이것은 단지 메소드를 즉시 호출하고 버튼을 눌러도 아무것도하지 않습니다.


4
frame = Tk.Frame (master = win) .grid (row = 1, column = 1) # Q. frame 값은 무엇입니까?
noob oddy

답변:


265

필자는 개인적 lambdas으로 그러한 시나리오에서 사용하는 것을 선호합니다 . 왜냐하면 imo가 더 명확하고 간단하며 호출 된 메소드를 제어 할 수없는 경우 많은 래퍼 메소드를 작성하도록 강요하지는 않지만 맛의 문제입니다.

그것이 람다로하는 방법입니다 (기능 모듈에 카레 구현이 있으므로 사용할 수도 있습니다).

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

11
여전히 래퍼 메소드를 작성 중이며 인라인으로 수행 중입니다.
agf

53
someNumber 가 실제로 많은 버튼을 생성하는 루프 내에서 값을 변경하는 변수 인 경우에는 작동하지 않습니다 . 그런 다음 각 버튼은 버튼을 만들 때의 값이 아닌 someNumber에 마지막으로 지정된 값으로 action ()을 호출합니다 . partial이 경우 사용하는 솔루션 이 작동합니다.
Scrontch

1
이것은 나를 위해 잘 작동했습니다. 그러나 OP 문이 왜 "This just invokes the method immediately, and pressing the button does nothing"발생 하는지 설명 할 수 있습니까?
Tommy

17
@ Scrontch 나는 Tkinter 사용자가 당신이 언급 한 함정에서 결코 느끼지 못한 초보자 수를 궁금해합니다! 여하튼 관용구 를 사용하여 현재 값을 캡처 할 수 있습니다callback=lambda x=x: f(x)fs = [lambda x=x: x*2 for x in range(5)] ; print [f() for f in fs]
gboffi

1
@Voo 위의 "구식 파이썬 사람들은 아마도 람다에 대한 기본 매개 변수 할당을 고수 할 것입니다"라는 의미는 무엇입니까? 나는 람다가 작동하지 않았으므로 이제 부분적으로 사용합니다.
Klamer Schutte

99

다음 과 같이 partial표준 라이브러리 functools 를 사용하여 수행 할 수도 있습니다 .

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

33
또는 더 짧음 :button = Tk.Button(master=frame, text='press', command=partial(action, arg))
Klamer Schutte

괴롭힘에 대해 죄송하지만 두 개 이상의 주장이있는 경우 어떻게 하시겠습니까?
으깬 감자

5
action_with_args = partial(action, arg1, arg2... argN)
Dologan

람다는 나를 위해 작동하지 않았기 때문에이 접근법을 취할 것입니다.
Zaven Zareyan

19

GUI 예 :

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'])

command옵션을 callbackin에서 와 같이 호출하려는 메소드에 대한 참조로 설정해야 한다고 생각할 수 있습니다 button_press_handle.


버튼을 눌렀을 때 메소드 호출 ( 콜백 )

논증 없이

따라서 print버튼을 눌렀을 때 무언가를 원한다면 설정해야합니다.

btn['command'] = print # default to print is new line

에주의를 기울이 부족()print있음을 의미 생략 방법 : "이것은 내가 누르면 통화 할 메서드의 이름입니다 . 단지 바로이 순간을 호출하지 않습니다" 그러나 인수에 대한 인수를 전달하지 않았으므로 인수 print없이 호출 할 때 인쇄 된 내용을 인쇄했습니다.

인수 (들)

이제 버튼을 누를 때 호출메소드에 인수를 전달 하려면 익명 함수를 사용할 수 있습니다.이 함수 는 다음과 같이 내장 메소드의 경우 람다 문 으로 만들 수 있습니다. 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실제로는 불가능 합니다 . 그것은 않습니다 만 하지 아무 곳이나 그 함수 외부. 따라서 현재 범위에서 액세스 할 수있는 개체를 수정 해야합니다 .returnbutton_press_handlecallback()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()

거울


10

함수 인수에 기본값을 제공하는 파이썬의 능력은 우리에게 탈출구를 제공합니다.

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

4
이렇게해도 문제가 해결되지 않습니다. 모두 동일한 기능을 호출하지만 다른 인수를 전달해야하는 3 개의 버튼을 만드는 경우 어떻게됩니까?
Bryan Oakley

함수를 반환하는 함수를 만들 수 있습니다.
MarrekNožka

나는이 더 이상 활성화되지 알고 있지만 내가 여기에 링크 stackoverflow.com/questions/35616411/... ,이 람다 표현식을 사용하는 것과 동일한 방식으로 작동, 당신은 결정과 같은 방법으로 각 버튼에 대한 기능을 정의 할 수 있습니다 각 버튼의 람다 식
Tadhg McDonald-Jensen

첫 번째 코드 예제를 계속 변경 myX하고 myY완벽하게 작동 하는 루프에 넣으면 대단히 감사합니다.
Tadhg McDonald-Jensen

3

Matt Thompsons의 답변 : 클래스를 호출 가능하게 만들어 함수 대신 사용할 수 있습니다.

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

2

메소드를 즉시 호출하고 버튼을 눌러도 아무것도 수행되지 않는 이유 action(somenumber)는 평가되고 리턴 값이 버튼의 명령으로 간주되기 때문입니다. 따라서 action무언가가 run and returns이라는 것을 인쇄 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()

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

나는 이것을 고쳐야한다고 믿는다.


2

가장 좋은 방법은 다음과 같이 람다를 사용하는 것입니다.

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

2

나는 매우 늦었지만 여기에 그것을 달성하는 매우 간단한 방법이 있습니다.

import tkinter as tk
def function1(param1, param2):
    print(str(param1) + str(param2))

var1 = "Hello "
var2 = "World!"
def function2():
    function1(var1, var2)

root = tk.Tk()

myButton = tk.Button(root, text="Button", command=function2)
root.mainloop()

다른 기능에서 사용하려는 기능을 랩핑하고 버튼 누름에서 두 번째 기능을 호출하면됩니다.


코드를 넣어함에 var1var2주요 모듈에, 당신은 건너 뛸 수 있습니다 function1전혀 넣어 print에서 문을 function2. 내가 얻지 못한 다른 상황을 언급합니까?
Brom

2

람다는 모두 좋고 훌륭하지만 이것을 시도 할 수도 있습니다 (for 루프 btw에서 작동).

root = Tk()

dct = {"1": [*args], "2": [*args]}
def keypress(event):
    *args = dct[event.char]
    for arg in args:
        pass
for i in range(10):
    root.bind(str(i), keypress)

바인딩이 설정되면 키 누름이 이벤트를 인수로 전달하기 때문에 작동합니다. 그런 다음 event.char"1"또는 "UP"효과를 얻는 것처럼 이벤트에서 속성을 호출 할 수 있습니다 . 이벤트 속성 이외의 인수 또는 여러 인수가 필요한 경우 사전을 만들어 저장할 수 있습니다.


2

전에도이 문제가 발생했습니다. 람다를 사용할 수 있습니다.

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

1

다음과 같이 더 많은 작업을 수행 해야하는 경우 람다를 사용하여 항목 데이터를 명령 함수에 전달하십시오 (일반적으로 만들려고 했으므로 적응하십시오).

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

이벤트의 정보를 버튼 기능으로 전달합니다. 이것을 작성하는 더 많은 Pythonesque 방법이있을 수 있지만 그것은 나를 위해 작동합니다.


1

JasonPy-몇 가지 ...

루프에 버튼을 넣으면 반복해서 만들어 질 것입니다 ... 아마도 당신이 원하는 것이 아닙니다. (아마도) ...

항상 마지막 인덱스를 얻는 이유는 프로그램을 시작할 때가 아니라 클릭 할 때 실행되는 람다 이벤트 때문입니다. 나는 당신이하고있는 일을 100 % 확신하지 못하지만 값이 만들어지면 저장하고 나중에 람다 버튼으로 호출하십시오.

예 : (이 코드를 사용하지 말고 예제)

for entry in stuff_that_is_happening:
    value_store[entry] = stuff_that_is_happening

그럼 당신은 말할 수 있습니다 ....

button... command: lambda: value_store[1]

도움이 되었기를 바랍니다!


1

한 가지 간단한 방법은 다음 구문 buttonlambda같이 구성 하는 것입니다.

button['command'] = lambda arg1 = local_var1, arg2 = local_var2 : function(arg1, arg2)

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.


1

당신은 사용해야합니다 lambda:

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

1

람다 사용

import tkinter as tk

root = tk.Tk()
def go(text):
    print(text)

b = tk.Button(root, text="Click", command=lambda: go("hello"))
b.pack()
root.mainloop()

산출:

hello
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.