내장된(Embedded) 파이썬 셸
from wxPython.wx import * from PyCrust.shell import Shell class ShellFrame(wxFrame): def __init__(self, parent=None, id=-1, title="PyCrust Minimus"): wxFrame.__init__(self, parent, id, title) self.shell = Shell(parent=self) class App(wxApp): def OnInit(self): self.frame = ShellFrame() self.frame.Show(true) self.SetTopWindow(self.frame) return true def main(): application = App(0) application.MainLoop() if __name__ == "__main__": main()파이썬카드는 이것을 한 단계 더 발전시켜 모든 파이썬카드 애플리케이션에 자동으로 파이크러스트 셸과 네임스페이스 뷰어를 포함한다. 게다가 이벤트 메시지 감시기, 로그기록기, 특성 편집기 등도 포함한다. 파이썬카드로 구축된 애플리케이션의 사용자는 보통 이러한 실행시간 도구들을 볼 수 없지만, 표준 모둠의 명령어 라인 선택사항으로 그 도구들을 보여줄 수 있다. 실행시간 도구모음은 특히 개발중이나 디버깅 중에 편리하다. 두 경우 모두 구이(GUI) 개발 환경에서 자주 결여되고 있는 투명함을 제공한다. 예를 들어 아래 그림은 모든 실행시간 도구들이 적재된 Counter 예제를 보여 주고 있다.
파이크러스트 셸을 애플리케이션에서 할 수 있게 만들어주는 코드(그리고 그 반대도)는 다음과 같이 간단하다.
class PyCrustFrame(MyMiniFrame): def __init__(self, parent, ID, title, pos, size, parentApp): MyMiniFrame.__init__(self, parent, ID, title, pos, size) parentApp.shell = PyCrust.shell.Shell(self, -1) parentApp.shell.interp.locals["pcapp"] = parentApp self.parentApp = parentApp wx.EVT_CLOSE(self, self.onCloseMe) def onCloseMe(self, evt): self.Show(0)셸 프레임(shell frame)이 wxPython MiniFrame으로 만들어진다. 파이크러스트 셸이 그 프레임에 부착된다. 애플리케이션 그 자체는 그 셸의 지역 네임스페이스에 "pcapp"으로 부착된다. 위의 그림에서 보듯이, 지금부터는 애플리케이션이 실행되는 동안에, 그 애플리케이션에 접근할 수 있다. 따라서 창 그리고 그 창의 메뉴와 버튼, 그 메뉴와 버튼의 메소드와 속성 등등에 접근할 수 있다. 이 덕분에 파이크러스트 파이썬 셸에서 거의 모든 파이썬 명령어들을 실행할 수가 있다.
참고 도서 |
from wxPython import wx ID_FILE_EXIT = wx.NewId() ID_COUNTER_INCREMENT = wx.NewId() ID_COUNTER_DECREMENT = wx.NewId() ID_COUNTER_RESET = wx.NewId() class MyApp(wx.wxApp): def OnInit(self): frame = wx.wxFrame(wx.NULL, -1, "PythonCard Counter Tutorial", size=(204, 160)) self.frame = frame panel = wx.wxPanel(frame, -1) self.resetBtn = wx.wxButton(panel, -1, "Reset", (10, 68)) self.decrBtn = wx.wxButton(panel, -1, "Decrement", (10, 38)) self.incrBtn = wx.wxButton(panel, -1, "Increment", (10, 8)) # 이 이벤트 엮기(binding)는 파이썬카드 프레임워크에 의해 자동으로 이루어진다. wx.EVT_BUTTON(panel, self.resetBtn.GetId(), self.OnResetMouseClick) wx.EVT_BUTTON(panel, self.decrBtn.GetId(), self.OnDecrMouseClick) wx.EVT_BUTTON(panel, self.incrBtn.GetId(), self.OnIncrMouseClick) # 사후 초기화(post initialization) self.incrBtn.SetDefault() self.field1 = wx.wxTextCtrl(panel, -1, "42", (127, 19), (55, 46), wx.wxTE_READONLY) # 콘트롤 하나가 만들어지고 나면, 파이썬카드는 컴포넌트가 지원하는 속성들에 대하여 # 사후 초기화(post initialization)를 단행한다. wxPython에서 이러한 과정들은 추가로 실행되는 작업이다. font = self.field1.GetFont() font.SetPointSize(24) font.SetFaceName("MS Sans Serif") font.SetFamily(wx.wxSWISS) self.field1.SetFont(font) # "File" 메뉴를 만들어라 file_menu = wx.wxMenu() file_menu.Append(ID_FILE_EXIT, "E&xit\tAlt+X") # "Counter" 메뉴를 만들어라 counter_menu = wx.wxMenu() counter_menu.Append(ID_COUNTER_INCREMENT, "Increment") counter_menu.Append(ID_COUNTER_DECREMENT, "Decrement") counter_menu.Append(ID_COUNTER_RESET, "Reset") # 이제 방금 만든 두 개의 메뉴를 보유할 메뉴 바가 필요하다. menu_bar = wx.wxMenuBar() menu_bar.Append(file_menu, "&File") menu_bar.Append(counter_menu, "Counter") # 메뉴 바를 설정하라 (시스템에 작업완료 사실을 알린다) frame.SetMenuBar(menu_bar) # EVT_MENU를 사용하여, 각 메뉴 항목에 대한 식별자(identifier)를 # 그 메뉴 항목이 선택될 때 호출될 메소드와 연관짓는다. wx.EVT_MENU(self, ID_FILE_EXIT, self.OnFileExit) # 버튼들에 대하여 정의된 메소드들을 재사용할 수 있다 wx.EVT_MENU(self, ID_COUNTER_INCREMENT, self.OnIncrMouseClick) wx.EVT_MENU(self, ID_COUNTER_DECREMENT, self.OnDecrMouseClick) wx.EVT_MENU(self, ID_COUNTER_RESET, self.OnResetMouseClick) frame.Show(1) self.SetTopWindow(frame) return 1 def OnIncrMouseClick(self, event): endValue = int(self.field1.GetValue()) + 1 self.field1.SetValue(str(endValue)) def OnDecrMouseClick(self, event): endValue = int(self.field1.GetValue()) - 1 self.field1.SetValue(str(endValue)) def OnResetMouseClick(self, event): self.field1.SetValue("0") def OnFileExit(self, event): self.frame.Close() app = MyApp(0) app.MainLoop()보시다시피 이벤트(events)들과 그 핸들러(handlers)들을 연관짓는데 상당한 부담(overhead)이 수반된다. 똑같은 애플리케이션을 파이썬카드로 코딩하면 실제로 두 개의 파일로 나뉘어진다. 한 파일은 애플리케이션 로직을 담고 있고 다른 하나는 모든 구이(GUI) 컴포넌트들의 속성들을 기술하는 리소스(resource) 파일이다. 다른 말로 하면, 형태와 기능을 분리하고 있는 것이다. 애플리케이션 코드는 다음과 같다.
from PythonCardPrototype import model class Counter(model.Background): def on_menuFileExit_select(self, event): self.Close() def on_menuCounterIncrement_select(self, event): startValue = int(self.components.field1.text) endValue = startValue + 1 self.components.field1.text = str(endValue) def on_menuCounterDecrement_select(self, event): startValue = int(self.components.field1.text) endValue = startValue - 1 self.components.field1.text = str(endValue) def on_menuCounterReset_select(self, event): self.components.field1.text = "0" def on_incrBtn_mouseClick(self, event): startValue = int(self.components.field1.text) endValue = startValue + 1 self.components.field1.text = str(endValue) def on_decrBtn_mouseClick(self, event): startValue = int(self.components.field1.text) endValue = startValue - 1 self.components.field1.text = str(endValue) def on_resetBtn_mouseClick(self, event): self.components.field1.text = "0" if __name__ == "__main__": app = model.PythonCardApp(Counter) app.MainLoop()어떻게 파이썬카드가 이벤트들을 적절한 핸들러로 엮을까? wxPython 예제를 살펴 보면, 어느 정도는 일관성을 가지고 이벤트 핸들러의 이름을 짓고 있는 것을 볼 수 있다. 예를 들어 "OnIncrMouseClick"과 "OnDecrMouseClick"과 같이 말이다. 이런 일관성이 필수적인 것은 아니지만, 관행상 상당히 전형적이다. 파이썬카드는 일관성 있는 이름짓기 전략의 이점을 활용하여 자동으로 핸들러와 그 핸들러를 촉발시키는 이벤트에 연관짓는다.
{"stack":{"type":"Stack", "name":"Counter", "backgrounds": [ {"type":"Background", "name":"bgcounter", "title":"PythonCard Counter Tutorial", "size":(204, 160), "menubar": {"type":"MenuBar", "menus": [ {"type":"Menu", "name":"menuFile", "label":"&File", "items": [ {"type":"MenuItem", "name":"menuFileExit", "label":"E&xit\tAlt+X", }, ] }, {"type":"Menu", "name":"menuCounter", "label":"Counter", "items": [ {"type":"MenuItem", "name":"menuCounterIncrement", "label":"Increment", }, {"type":"MenuItem", "name":"menuCounterDecrement", "label":"Decrement", }, {"type":"MenuItem", "name":"menuCounterReset", "label":"Reset", }, ] }, ] }, "components": [ {"type":"Button", "name":"resetBtn", "position":(10, 68), "label":"Reset", }, {"type":"Button", "name":"decrBtn", "position":(10, 38), "label":"Decrement", }, {"type":"Button", "name":"incrBtn", "position":(10, 8), "default":1, "label":"Increment", }, {"type":"TextField", "name":"field1", "position":(127, 19), "size":(55, 46), "editable":0, "font":{"size": 24, "family": "sansSerif"}, "text":"42", }, ] # end components } # end background ] # end backgrounds } }파이썬카드 애플리케이션을 애플리케이션 코드와 애플리케이션 리소스 파일 두 부분으로 나눔으로써, 구이(GUI) 개발에 관련된 권태와 시간소비를 약간이나마 제거하였다. 동시에, 리소스 정보를 표준 파이썬 구조(사전, 리스트, 터플, 등등)로 저장하면 편집 도구를 추가로 만들 수 있거나 파이썬으로 작성된 맞춤 유틸리티로 리소스 파일을 조작할 수 있다. 리소스 편집기를 한 번 살펴보고 어떻게 작동하는지 알아보자.
그리고 다음의 또다른 스크린 샷은 컴포넌트 메뉴 옵션을 보여준다.
(당연히 궁금하게 여기겠지만 리소스 편집기는 그 자체로 자신의 리소스 파일을 가진 파이썬카드 애플리케이션이다. 사실, 리소스 편집기는 바로 자신의 리소스 파일을 편집하는데 사용된다.)
이전 글 : 무선 메시지 서비스 V: 단말 착신 단문 메시지 예
다음 글 : IPv6: 다시 타오르는 인터넷 혁명
최신 콘텐츠