Searching for 파이썬
1 articles found.

  1. 2009/01/22 파이썬 Tkinter에서 프로토콜 핸들러 사용 (6)


파이썬 Tkinter에서 프로토콜 핸들러 사용

2009/01/22 20:38  로키 TAG , ,
한동안 안하다가 조금씩이라도 해서 완성하자는 생각으로 코딩 프로젝트를 다시 잡았다. 그 과정에서 생긴 문제를 하나 해결해서 적어본다.

이 IRC 클라이언트를 만들면서 (가제 PRC) 처음부터 의도한 것은 기존 IRC 클라이언트보다 더 사용하기 쉽게 하자는 생각이었는데, 그 일환으로 초대 (INVITE) 이벤트도 텍스트 중심이 아닌 그래픽 인터페이스 중심으로 처리했다. 누군가에게 초대가 들어오면 그 사실만 알리는 게 아니라 초대받은 채널에 바로 입장할 수 있는 선택창을 띄우는 것.

초대받은 스크린샷

PRC에서 초대를 받았을 때 뜨는 메시지


그런데 여기서 문제가 생겼다. 어느쪽 선택지를 고르든 무조건 연결이 끊어지는 결과가 발생하는 것. 왜 그럴까 하고 소스를 뒤지다가 원인을 발견했다. 프로그램 창을 닫으면 서버 연결을 끊는 이벤트 바인딩을 넣어놓았는데, 그 바인딩을 메시지박스에서 계승하고 있던 게 문제였다. 다음은 관련 코드.

class App:

    def __init__(self, master):
        """초기 위젯 렌더링"""

        self.master = master
        #전체 창을 self.master 변수로 설정해서 같은 클래스 내 다른 함수에서도 부를 수 있게 한다

        self.master.bind("<Destroy>",self.closeWindow)
        #요 부분이 문제였다. closeWindow 함수는 연결을 끊는 함수인데 메시지박스에서 Yes를 선택하든 No를 선택하든 마찬가지로 창을 닫는 이벤트이니까 (<Destroy>) 같은 closeWindow 함수를 발동시킨다.

    #중략

    def closeWindow(self,event=None):
        """창이 닫히면 연결 끊기"""

        if self.connected:
            self.closeConnect()
            #연결이 되어 있다면 끊으라는 명령

    #후략


unbind로 바인딩을 끊으려고 해도 tkMessageBox 모듈로는 그게 좀 애매했다. tkMessageBox 모듈은 이런 식으로 불러오게 되어 있다.

        import tkMessagebox
        if tkMessageBox.askyesno(receivedInvite,askWhetherJoin):
            self.joinChannel(channel)

위젯이면 unbind를 할 수 있겠지만 위젯이 아니라 모듈로 바로 작업하는 거라서 그렇게도 할 수 없었다. 그렇다고 창을 닫을 때 동시에 서버 연결을 끊지 않으면 핑 타임아웃이 될 때까지는 같은 닉으로 재접속할 수 없으므로 사용하기 쉬운 IRC 프로그램을 만든다는 취지에도 어울리지 않았다.

그래서 검색하다가 발견한 것이 윈도우 매니져 프로토콜이었다. 창 닫는 버튼을 누른다고 바로 창을 닫는 대신 다른 이벤트를 먼저 발생시키는 이벤트라고 한다. 즉, 창을 닫으면 지정 함수를 발동시키는 게 아니라 사용자가 창을 닫는다는 명령을 내리면 함수를 발동시킨다는 미묘하면서도 중요한 차이다.

예시를 보고 바인딩 대신 프로토콜 핸들러로 바꿔본 결과는 성공. 서버 접속을 끊는 함수 바인딩이 메시지박스에 계승되지 않아서 원하는 효과를 낼 수 있었다.

class App:

   def __init__(self, master):
        """초기 위젯 렌더링"""

       self.master = master

        self.master.protocol("WM_DELETE_WINDOW",self.closeWindow)
        #바인딩 대신 프로토콜 핸들러로 바꾸었다

    #중략

   def closeWindow(self,event=None):
        """창 닫으라는 명령을 받으면 연결 끊고 창 닫기"""

       if self.connected:
           self.closeConnect()
            #연결이 되어 있다면 끊으라는 명령

        self.master.event_generate("<Destroy>")
        #그리고 창을 닫는다

    #후략


해피엔딩~ 초대받은 채널에 입장을 선택하면 자동으로 입장하고, 거절하면 입장하지 않는다. 어느 쪽이든 연결은 끊어지지 않는다. 이벤트 바인딩은 메시지 박스에 계승이 되고 프로토콜 핸들러는 안 되는 이유는 알 듯 말 듯 하면서 잘 모르겠지만(..) 어쨌든 좋은 게 좋은 거 아닌가.

자동입장한 스크린샷

접속 해제 없는 자동 입장 성공!


이런 식으로 천천히 작업하다 보면 언젠가는 완성을 볼 수 있겠지. 그러다 보면 코딩도 좀 늘어 있을까. 몇 달만에 본 소스인데도 막상 작업을 시작하니 대충 뭘 했는지 생각나는 거 보면 역시 배우는 방법 중에서는 해보는 게 으뜸인 듯 싶다.
2009/01/22 20:38 2009/01/22 20:38
TOP
  1. lhovamp
    2009/01/23 08:39 PERMALINK EDIT/ERASE REPLY

    자. 어서 닭둘기를 대체해 주세요 (먼산)

    • 로키
      2009/01/24 20:44 PERMALINK EDIT/ERASE

      다 하면 IRC쪽은 적어도 RPG용으로는 피진보다 낫겠고, IRC 서버에서 받는 정보의 한계 때문에 이걸로 MSN을 대체하기는 힘들겠지만... 좀 재밌는 생각이 하나 떠오르긴 하네. IRC 클라이언트이지만 친구 목록과 온라인 상태를 표시할 수는 있을지도. 비록 완전 실시간은 아니겠지만 말야.

  2. 2009/01/24 10:53 PERMALINK EDIT/ERASE REPLY

    로키님은 여전히 소스 코딩 작업에서 헤어 나오지 못하셨군요.^^
    오랜만에 들렸습니다.
    새해 인사하려구요.
    올 한해에도 건강하시고 복 많이 받으세요.^_______^

  3. orches
    2009/01/29 20:40 PERMALINK EDIT/ERASE REPLY

    잘 지내셨나요? 오랜만에 인사하러 들렀습니다.
    새해 복 많이 받으셔요 ^ (너무 오랜만에 드린 인사라.. 쟤 누구?.. 하실 것 같 ;ㅅ;)
    와! 소스 코팅 중이셨군요!! 막 신기신기하답니다.. ^^

    • 로키
      2009/01/30 15:56 PERMALINK EDIT/ERASE

      이야 오랜만입니다. 잘 지내셨는지..^^ 블로그에 업데이트도 하시고, 조금은 여유가 생기신 것 같아서 좋네요.

Write a comment

[로그인][오픈아이디란?]

submit