Program Tip

Button 매개 변수 "command"가 선언 될 때 실행되는 이유는 무엇입니까?

programtip 2020. 12. 12. 12:19
반응형

Button 매개 변수 "command"가 선언 될 때 실행되는 이유는 무엇입니까?


내 코드는 다음과 같습니다.

from Tkinter import *

admin = Tk()
def button(an):
    print an
    print 'het'

b = Button(admin, text='as', command=button('hey'))
b.pack()
mainloop()

버튼이 작동하지 않고 내 명령없이 'hey'와 'het'을 한 번 인쇄 한 다음 버튼을 눌러도 아무 일도 일어나지 않습니다.


이 코드를 고려하십시오.

b = Button(admin, text='as', command=button('hey'))

다음과 정확히 동일합니다.

result = button('hey')
b = button(admin, text='as', command=result)

command옵션은 함수에 대한 참조를 가져 오므로 함수 이름을 전달해야한다는 멋진 방법입니다. 참조를 전달하려면 괄호 나 인수를 사용하지 않고 이름 만 사용해야합니다. 예를 들면 :

b = Button(... command = button)

"hey"와 같은 매개 변수를 전달하려면 약간의 추가 코드를 사용해야합니다.

  • 인수없이 호출 할 수있는 중간 함수를 만든 다음 button함수 를 호출 할 수 있습니다.
  • 를 사용 lambda하여 익명 함수 라고 하는 것을 만들 수 있습니다 . 모든면에서 이름이없는 것을 제외하고는 함수입니다. lambda명령 을 호출하면 생성 된 함수에 대한 참조반환 됩니다 command. 즉, 버튼 에 대한 옵션 값으로 사용할 수 있습니다 .
  • functools.partial 을 사용할 수 있습니다.

나를 위해, 어떤 사람들은 이해하기 더 쉽다고 생각하지만 lambda추가 수입이 필요하지 않기 때문에 가장 간단합니다 .functools.partialfunctools.partial

button인수로 함수를 호출하는 람다 함수를 만들려면 다음과 같이하면됩니다.

lambda: button('hey')

기능적으로 다음과 같은 함수로 끝납니다.

def some_name():
    button('hey')

앞서 말했듯이, lambda이 이름없는 함수에 대한 참조를 반환합니다. 참조는 command옵션에서 기대 하는 것이므로 lambda버튼을 만들 직접 사용할 수 있습니다 .

b = Button(... command = lambda: button('hey'))

이 사이트에는 일반적으로 람다에 대한 흥미로운 의견이 많이있는 질문이 있습니다. Python 람다가 유용한 이유 질문을 참조하세요 . . 동일한 토론에는 콜백에 변수를 전달해야 할 때 루프에서 람다를 사용하는 방법을 보여주는 답변이 있습니다.

마지막으로 effbot.org의 Tkinter 콜백 섹션 에서 멋진 자습서를 참조하십시오. 람다의 범위는 매우 적지 만 정보는 여전히 유용 할 수 있습니다.


명령으로 사용할 수있는 매개 변수없이 함수를 생성해야합니다.

b = Button(admin, text='as', command=lambda: button('hey'))

이 문서의 "콜백에 인수 전달"섹션을 참조하십시오 .


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옵션으로 설정해야 우리가 원하는 방법에 대한 참조가 유사하게 호출 할 callback에서 button_press_handle.


버튼을 눌렀을 때 메서드 호출 ( Callback )

인수 없이

따라서 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)

버튼을 눌렀을 때 여러 메서드 호출

인수 없이

using 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으로 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()

거울


엔진은 "... command = ..."줄에 값을 할당 할 때 함수의 결과를 평가합니다.

"명령"은 함수가 반환 될 것으로 예상하기 때문에 람다를 사용하면 평가 중에 "명령"으로 반환되는 Anomymous 함수가 생성되므로 작업을 수행 할 수 있습니다. 자신 만의 함수를 코딩 할 수도 있습니다. 또한 작업을 수행합니다.

이것은 람다가 있고 람다가없는 예입니다.

#!/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 "\n"
    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 "\n"


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

함수의 입력이나 괄호로 키워드 나 인수를 사용하지 마십시오. 그것은 매우 쉬운 해결책입니다.


button('hey') 콜백으로 설정하지 않고 함수를 호출합니다.


이것은 내 해결책입니다.

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

기본적으로 우리가하는 일은 매개 변수로 함수를 정의한 다음 매개 변수없이 함수 내에서 호출하는 것입니다.

참고 URL : https://stackoverflow.com/questions/5767228/why-is-button-parameter-command-executed-when-declared

반응형