사건 주도형 프로그래밍

지금까지 우리는 배치 지향 프로그래밍을 살펴 보고 있는 중이었다. 기억하라. 프로그램은 '배치 지향적'일 수 있어서, 시작하고 나서, 무언가 하고 멈춘다, 또는 '사건 주도형'일 수 있어서, 시작하고 나서, 사건을 기다리고 멈추라고 명령을 받을 때 멈춘다 - 사건에 의해서. 어떻게 우리는 사건 주도형 프로그램을 만드는가? 우리는 이것을 두 가지 관점으로 살펴 볼 것이다 - 첫째로 우리는 사건 환경을 모사해보고 그리고 나서 우리는 아주 간단한 구이(GUI)프로그램을 만들 것이다. 그 구이 프로그램은 사건을 만들어 내는 환경과 운영체제를 사용한다.

사건을 모사하는 회돌이

모든 사건 주도형 프로그램은 어디에선가 사건을 접수하고 처리하는 회돌이를 가지고 있다. 실제적으로 모든 구이 프로그램에 일어나는 것과 같이, 사건은 운영체제에 의해서 만들어지거나, 혹은 카메라 등등에 사용되는 것과 같은 내장 제어 시스템의 경우와 같이, 프로그램 자체가 사건을 찾기도 한다.

우리는 정확하게 한가지 종류의 사건을 - 키보드 입력을 - 기다리고 그 결과를 어떤 종료 사건이 접수될 때까지 처리하는 프로그램 하나를 작성할 것이다. 우리의 경우에 종료 사건은 공백 키가 될 것이다. 우리는 들어오는 사건들을 대단히 간단한 방식으로 처리할 것이다 - 우리는 그 키에 대한 아스키 코드를 단순하게 출력할 것이다. 우리는 이것을 위하여 베이직을 사용할 것인데 왜냐하면 베이직은 뛰어나며, 쉽게 함수를 사용하여 키를 한번에 읽을수 있기 때문이다 - INKEY$로.

먼저 우리는 프로그램의 몸체를 구현한다. 그것은 간단히 사건을 모으는 회돌이를 시작하여 그리고 유효한 사건이 탐지되면 사건 처리 루틴을 호출한다.


' Declare the subroutines that will handle the events
DECLARE SUB dokeyevent (keypress AS STRING)
DECLARE SUB doquitevent (keypress AS STRING)

' First, clear the screen of clutter then warn the user
' of what to do to quit
CLS
PRINT "Hit space to end..."
PRINT

' Now loop forever
WHILE 1
        ky$ = INKEY$
        length = LEN(ky$)
        IF length <> 0 THEN
        ' send events to event handling functions
            IF ky$ <> " " THEN
                CALL doKeyEvent(ky$)
            ELSE
                CALL doQuitEvent(ky$)
            END IF
        END IF
WEND

주목할 것은 사건에 대하여 무엇을 하는 지는 주 몸체에게 별로 관심사항이 아니라는 것이다, 그것은 단순히 사건을 모아서 사건들을 사건 처리자에게 넘겨준다. 사건을 나포하고 처리하는 이 독립성은 사건 주도 프로그래밍의 가장 중요한 능력이다.

이제 우리는 두개의 사건 처리자를 구현할 수 있다. 첫 째로, " doKeyEvent "는 단순하게 눌려진 키의 아스키 값을 출력한다:

SUB doKeyEvent (keypress AS STRING)
    ' print valid keystrokes
    length = LEN(keypress)
    IF length = 1 THEN 'its simple ASCII
       PRINT ASC(keypress)
    ELSE
       IF length = 2 THEN
          'its non alphanumeric so use the 2nd char 
          PRINT ASC(MID$(keypress, 2, 1))
       END IF
    END IF
END SUB

doQuitEvent 는 시시하다 - 그것은 단지 그 프로그램을 멈춘다 !

SUB doQuitEvent (keypress AS STRING)
    STOP
END SUB

우리가 이것을 많은 프로젝트에서 사용하기 위하여 프레임워크로 이것을 작성한다면 우리는 아마도 초반부에 initialisation함수를 그리고 후반부에 cleanup 함수를 포함하게 될 것이다. 그러면 프로그래머는 그 회돌이 부분을 사용할 수 있고 자신만의 초기화, 처리 그리고 청소 함수를 제공할 수 있다.

회돌이 부분이 운영체제의 환경에 내장된다는 점에서 그것은 정확히 대부분의 구이(GUI) 형태의 환경이 하는 것이며 혹은 프레임워크(운영체제)와 어플리케이션은 어떤 면에서 상호간에 필요하여 사건 처리 함수를 제공하고 그리고 이것을 낚아 채서 사건 회돌이로 집어 넣을 수 있다.

그것을 실행해서 파이썬의 Tkinter 구이(GUI) 라이브러리를 탐험해 보자.

GUI 프로그램

이 연습문제를 위해서 우리는 파이썬 Tkinter 도구를 사용할 것이다. 이것은 파이썬이 Tkinter 툴킷을 포장한 것으로 원래는 Tcl에 대한 확장으로 작성되어 졌으며 또한 펄에도 사용가능하다. 파이썬 버젼은 객체지향 프레임워크이며 그것은, 나의 견해로는, 원래의 절차적인 Tk 버전보다 일하기가 훨씬 더 쉽다. 이러한 구이(GUI)의 양상에 관하여 나는 많이 다루지는 않을 것이다, 그 보다는 프로그래밍의 스타일에 집중하고 싶다 - Tkinter를 사용하여 사건 회돌이를 처리하고 프로그래머에게 기초적인 구이(GUI)를 작성하고 그리고는 사건들이 도착하는데로 그것들을 처리할 수 있도록 해주는데 집중하고 싶다.

예제에서 우리는 어플리케이션 클래스인 KeysApp를 생성한다. 그것은 __init__메쏘드 안에 구이(GUI)를 생성하고 공백키를 doQuitEvent메쏘드에 묶는다. 그 클래스는 또한 요구되는 doQuitEvent 메쏘드를 정의한다.

GUI 자체는 간단하게 텍스트 엔트리 위젯 widget으로 구성된다. 그의 기본적인 행위는 문자들을 스크린 위에 출력하는 것이다.

어플리케이션 클래스를 작성하는 것은 OO 사건 주도 프로그래밍에서는 매우 흔한 일이다. 왜냐하면 프로그램으로 보내어지는 사건의 개념과 객체에 보내어지는 메시지의 개념사이에는 많은 유사점이 있기 때문이다. 그 두개의 개념은 서로간에 아주 쉽게 짝짓기된다. 사건 처리 함수는 그런식으로 어플리케이션 클래스의 메쏘드가 된다.

클래스를 정의한 후에 우리는 간단하게 그것의 실체를 작성하고 그리고는 그것에 mainloop메시지를 보내기만 하면 된다.

그 코드는 다음과 같이 보인다:


# Use from X import * to save having to preface everything
# as tkinter.xxx
from Tkinter import *

# Create the application class which defines the GUI
# and the event handling methods
class KeysApp(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.txtBox = Text(self)
        self.txtBox.bind("", self.doQuitEvent)
        self.txtBox.pack()
        self.pack()

    def doQuitEvent(self,event):
        import sys
        sys.exit()


# Now create an instance and start the event loop running
myApp = KeysApp()
myApp.mainloop()

물론 베이직 버전에서 우리는, 우리가 여기서 한 것처럼 인쇄가능한 키의 영문숫자 버젼을 출력하는 것보다는 모든 키들의 아스키 코드를 출력했다. 우리는 아무런 방해없이 눌려진 모든 키들을 나포할 수 있고 같은 일을 할 수 있다. 그러기 위해서 우리는 다음 라인을 __init__ 메쏘드에 추가할 것이다:

self.txtBox.bind("< Key >", self.doKeyEvent)

그리고 사건을 처리하기 위해서는 다음의 메쏘드를 (추가 할 것이다):

def doKeyEvent(self,event):
    str = "%d\n" % event.keycode
    self.txtBox.insert(END, str)
    return "break"

주의 1: 키 값은 그 사건의 keycode 필드에 저장된다. 나는 그것을 발견하기 위해서 Tkinter.py 의 소스코드를 살펴 보아야만 했다... 호기심은 프로그래머의 가장 중요한 속성이라는 것을 기억하는지?

주의 2: return "break" 는 마법의 신호이다. Tkinter에게 그 위젯을 위해서 기본으로 지정된 사건 처리를 요청하지 못하도록 한다. 그 라인이 없다면, 그 텍스트 상자는 실제로 타이프되는 문자뒤에 아스키 코드를 출력할 것이며, 그것은 우리가 여기에서 원한 바가 아니다.

이것으로 지금은 충분하다. 이 책은 Tkinter를 위한 지침서를 의도하지 않는다. 그것은 다음 주제의 과제이다. 또한 Tk와 Tkinter의 사용법에 관한 책들도 있다.


Previous  Next  Contents
 

여러분이 이 페이지에 대하여 질문 혹은 제안사항이 있으면 다음 주소를 나에게 전자메일을 보내라: agauld@crosswinds.net