티스토리 뷰

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
Python,tkinter command & bind [명령어묶기와 사건묶기]
Python,tkinter,command,bind,curry,lambda

>> 명령어묶기(command) <<
명령어묶기란 Button과 같은 위젯에 메서드를 연결하여 이벤트를 발생시키는 것을 의미한다.
명령어묶기용 parameter인 command를 이용하여 위젯과 명령어를 연결시킨다.
모든 위젯에는 command존재하는 것이 아니므로, 필요에 따라서 아래에서 설명하고 있는 사건묶기(bind)를 이용하기도 한다.

ex) Python_tkinter_command_01.py
# -*- encoding:utf8 -*-
# Python version in the development environment 2.7.11
import os,sys,time
os.chdir(os.path.dirname(__file__))
from Tkinter import *

class MyApp:
    def __init__(self,parent):
        self.myparent=parent

        #--- mainframe 생성 ---
        self.mainframe=Frame(self.myparent)
        self.mainframe.pack()

        #--- button1 생성 ---
        self.button1=Button(self.mainframe,
                            text="OK",
                            bg="green",
                            command=self.button1click) #명령어묶기로 메서드를 지정
        self.button1.pack()

    #button1의 command에 사용된 함수
    def button1click(self):
        if self.button1['bg']=='green':
            self.button1['bg']='yellow'
        else:
            self.button1['bg']='green'

root = Tk()
myapp = MyApp(root)
root.mainloop()

실행화면




button1위젯 클릭시 버튼의 색이 변함

>> 사건묶기(bind) <<
사건묶기는 위젯, 사건, 사건처리자의 하나로 묶어주는것을 말한다.
ex) Python_tkinter_bind_01.py
# -*- encoding:utf8 -*-
# Python version in the development environment 2.7.11
import os,sys,time
os.chdir(os.path.dirname(__file__))
from Tkinter import *

class MyApp:
    def __init__(selfparent):
        self.myparent = parent

        #--- mainframe 생성 ---
        self.mainframe = Frame(self.myparent)
        self.mainframe.pack()

        #--- button1 생성 ---
        self.button1 = Button(self.mainframe,
                              text="OK",
                              bg="green",
                              command=self.button1click) #명령어묶기로 메서드를 지정
        self.button1.bind("<Return>"self.button1click_a) #사건묶기로 사건과 메서드를 지정
        self.button1.pack()

    #button1의 명령어묶기에 사용된 함수
    def button1click(self):
        if self.button1['bg'] == 'green':
            self.button1['bg'] = 'yellow'
        else:
            self.button1['bg'] = 'green'

    #button1의 사건묶기에 사용된 함수
    def button1click_a(selfevent):
        print event #인자로 받은 event출력
        self.button1click()

if __name__ == '__main__':
    root = Tk()
    myapp = MyApp(root)
    root.mainloop()

실행동작은 위의 명령어묶기와 동일하나, button1에 초점을 맞춘후 Enter키를 누르게 되면
사건묶기로 묶인 button1click_a메서드가 호출된다.
따라서 인자로 받은 event객체가 출력된다.

<tkinter.Event object at 0x00000000028D7828>
"<Return>" : Enter키 누름을 의미한다.

위의 예제의 사건묶기 동작을 좀더 기술적으로 설명하자면 button1에 초점이 맞추어진 상태에서 enter키를 누르게 되면, event객체가 발생하고 event객체를 인자하여 button1click_a메서드를 호출하게 된다. button1click_a메서드는 인자로받은 event객체를 print()내부함수를 이용하여 화면에 출력하고, 다시 button1click메서드를 호출한다.

button1click메서드가 호출되면, button1click메서드는 다시 button1의 parameter로 역호출이 이루어진다.
즉, button1click메서드는 button1['bg']메서드를 역호출하여 parameter값을 'yellow'로 지정하는것이다.

※ 여기서 알고 넘어가야할 2가지!
초점이란?
초점이란 단순하게 보면 선택된 상태를 의미한다.
즉, button1을 Enter키를 누르려고 하면, button1에 초점이 맞추어진 상태에서 enter키를 눌러야만 한다.
이는 어플리케이션을 실행후 Tab키를 이용하여 초점의 변화가 가능하고,
focus_force()메서드를 이용하면 어플리케이션 실행시 최초 초점의 위치를 잡아줄수 있다.

역호출함수란?
역호출함수란 사건처리자로 지정된 함수가 외부로 다시 호출이 이루어져 외부의 자원을 사용하는것을 말한다.
즉, 위의 예제에서도 button1click메서드는 외부의 self.button1['bg']에 역호출이 이루어진것이다.
또한, 함수내에서 다른 함수를 다시 호출할때도 역시 역호출이 이루어진다고 볼수 있다.
간단하게 생각하면 그리 어려운 문제가 아니지만, 명령어묶기, 사건묶기를 할때 역호출이 일어나 프로그래머 원하지 않는 방향으로 어플리케이션이 동작할수도 있다. 자세한 내용은 아래의 사건처리자에서 다루어 보도록 하겠다.

>> 사건처리자 <<
Button위젯이 4개가 있고, Button위젯을 클릭할때마다 자기의 text를 출력하는 어플리케이션을 만든다고 해보자,
여기서 각 Button위젯마다 함수를 만들어 실행하는것과 함수를 하나만 만들어서 Button위젯의 text를 인자로 넘겼을때, 어느것이 효율적인지는 프로그램을 만들지 않아도 알수 있을것이다.
하지만 명령어묶기나 사건묶기로 메서드를 지정할때 메서드객체를 지정해주어야 한다. 만약 메서드객체가 아닌 메서드호출로 지정이 되면, 사건처리자의 값으론 메서드호출로 나온 반환값이 연결이 되게 된다.
command=button1click : 함수객체를 command에 전달
command=button1click() : 함수호출을 하여 반환값을 command에 전달
따라서 사건처리자로 메서드를 연결하고 이에 인자값을 주고자 할때는 함수내포기법이나, lambda함수를 이용하게 된다.
우선 아래의 예제를 통하여 함수객체전달과 함수호출 전달의 차이점을 확인해보도록 하자
ex) Python_tkinter_event_01.py
# -*- encoding:utf8 -*-
# Python version in the development environment 2.7.11
from Tkinter import *

class MyApp:
    def __init__(selfparent):
        self.myparent = parent
        #--- mainframe 생성 ---
        self.mainframe=Frame(self.myparent)
        self.mainframe.pack()
        #--- button1생성 ---
        self.button1 = Button(self.mainframe,
                              text='Button1',
                              command=self.button1click) #함수객체
        self.button1.pack()
        #--- button2생성---
        self.button2 = Button(self.mainframe,
                              text='Button2',
                              command=self.button2click()) #함수호출
        self.button2.pack()

    def button1click(self):
        print "button1click"

    def button2click(self):
        print "button2click"

if __name__ == '__main__':
    print '어플리케이션실행'
    root = Tk()
    myapp = MyApp(root)
    root.mainloop()

위 예제를 실행해보면 어플리케이션이 실행이 되기도 전에 button2click메서드가 실행되는것을 알수 있다.
위에서 말한것처럼 button2위젯의 command parameter에 button2click의 반환값이 지정이 되므로, 이때 함수호출이 이루어져 print("button2click") 구문이 이루어지는 것이다. button1위젯을 클릭하면 함수객체로 전달이 되어 정상적으로 동작하는것을 알수 있다.

위에서 말한것처럼 Button위젯을 4개 생성후 각 Button위젯을 클릭할때마다 이벤트가 발생하는 예제를 생성후,
우선 각 Button위젯에 대입되는 함수를 4개 생성하는 예제를 본후, 함수내포기법을 이용하여, 다시 작성한 예제와, lambda함수를 이용하여 작성한 예제를 보도록 하겠다.

어플리케이션의 동작결과는 모두 같기 때문에, 결과보다는 코드를 중점으로 보도록 하길 바란다.

-. Button위젯에 각각 다른 함수가 지정된 경우
ex) Python_tkinter_event_02.py
# -*- encoding:utf8 -*-
# Python version in the development environment 2.7.11
from Tkinter import *

class MyApp:
    def __init__(selfparent):
        self.myparent = parent
        #--- mainframe 생성 ---
        self.mainframe = Frame(self.myparent)
        self.mainframe.pack()
        #--- button1생성 ---
        self.button1 = Button(self.mainframe,
                              text='Button1',
                              command=self.button1click)
        self.button1.pack()
        #--- button2생성---
        self.button2 = Button(self.mainframe,
                              text='Button2',
                              command=self.button2click)
        self.button2.pack()
        #--- button3생성---
        self.button2 = Button(self.mainframe,
                              text='Button2',
                              command=self.button3click)
        self.button2.pack()
        #--- button4생성---
        self.button2 = Button(self.mainframe,
                              text='Button2',
                              command=self.button4click)
        self.button2.pack()

    def button1click(self):
        print "button1click"

    def button2click(self):
        print "button2click"

    def button3click(self):
        print "button2click"

    def button4click(self):
        print "button2click"

if __name__ == '__main__':
    root = Tk()
    myapp = MyApp(root)
    root.mainloop()

-. 함수내포기법(curry)을 이용하여 코딩
함수내포기법이란?
가장 단순한 의미론, 함수를 사용하여 다른 함수를 구성하는 방법이다.
자세한 내용은 아래 URL에서 확인하길 바란다.
http://code.activestate.com/recipes/52549/

ex) Python_tkinter_event_03.py
# -*- encoding:utf8 -*-
# Python version in the development environment 2.7.11
from Tkinter import *

class curry#함수 내포 기법에 사용할 클래스
    def __init__(selffunc*args**kwargs):
        self.func = func  #함수
        self.pending = args[:] #인자
        self.kwargs = kwargs.copy() #사전형 인자

    def __call__(self*args**kwargs):
        if kwargs and self.kwargs:
            kw = self.kwargs.copy()
            kw.update(kwargs)
        else:
            kw = kwargs or self.kwargs
        return self.func(*(self.pending+args)**kw)

class MyApp:
    def __init__(selfparent):
        self.myparent = parent
        #--- mainframe 생성 ---
        self.mainframe = Frame(self.myparent)
        self.mainframe.pack()
        #--- button1생성 ---
        self.button1 = Button(self.mainframe,
                              text='Button1',
                              command=curry(self.buttonclick,"button1click"))
        self.button1.pack()
        #--- button2생성---
        self.button2 = Button(self.mainframe,
                              text='Button2',
                              command=curry(self.buttonclick,"button2click"))
        self.button2.pack()
        #--- button3생성---
        self.button2=Button(self.mainframe,
                            text='Button2',
                            command=curry(self.buttonclick,"button3click"))
        self.button2.pack()
        #--- button4생성---
        self.button2=Button(self.mainframe,
                            text='Button2',
                            command=curry(self.buttonclick,"button4click"))
        self.button2.pack()

    def buttonclick(self,text):
        print(text)

if __name__ == '__main__':
    root=Tk()
    myapp=MyApp(root)
    root.mainloop()

-. lambda함수를 이용하여 코딩
lambda함수란?
http://blog.naver.com/dudwo567890/130149884018

ex) Python_tkinter_event_04.py
# -*- encoding:utf8 -*-
# Python version in the development environment 2.7.11
from Tkinter import *

class MyApp:
    def __init__(self,parent):
        self.myparent=parent
        #--- mainframe 생성 ---
        self.mainframe=Frame(self.myparent)
        self.mainframe.pack()
        #--- button1생성 ---
        self.button1=Button(self.mainframe,
                            text='Button1',
                            command=lambda t="buton1click":self.buttonclick(t))
        self.button1.pack()
        #--- button2생성---
        self.button2=Button(self.mainframe,
                            text='Button2',
                            command=lambda t="buton2click":self.buttonclick(t))
        self.button2.pack()
        #--- button3생성---
        self.button2=Button(self.mainframe,
                            text='Button2',
                            command=lambda t="buton3click":self.buttonclick(t))
        self.button2.pack()
        #--- button4생성---
        self.button2=Button(self.mainframe,
                            text='Button2',
                            command=lambda t="buton4click":self.buttonclick(t))
        self.button2.pack()

    def buttonclick(self,text):
        print(text)

root=Tk()
myapp=MyApp(root)
root.mainloop()

※ lambda와 curry 어느것을 사용해야 하는가?
curry를 요청하는 코드는 상대적으로 직관적이며, 짧고 간단하다.
단점은 이것들을 사용하기 위해서는 프로그램에 코드를 삽입해 주어야 한다는 것이다.

lambda를 요청하는 코드는 코드의 가독성이 떨어지는 반면,
함수자체가 python에 내장되어 있으므로, 반입하기위해 특별히 해야할것이 없다는점이다.

선택은 사용자의 몫이다. 자기가 사용하기 편하고, 가장 친숙한것을 사용하자,
그리고 작업에 가장 적당하다고 여겨지는것을 사용하자


댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함