2010-12-29 3 views
1

저는 tkinter에서 개인적인 사용을위한 아주 작은 프로그램을 만들고 있습니다. 그리고 저는 정말 이상한 벽에 뛰어 들었습니다. 필자는 pywin32 바인딩과 tkinter를 혼합합니다. 왜냐하면 pywin32의 구문 및 명명 규칙과 관련이 없기 때문에 tkinter는 훨씬 적은 코드로 더 많은 작업을 수행 할 수 있습니다. pywin32 클립 보드 시청과 tkinter에서 내 프로그램의 반응 사이의 전환에서 이상한 일이 발생합니다.약간의 PyWin32와 혼합 할 때이 유효한 Tkinter 코드가 왜 충돌합니까?

내 창과 모든 컨트롤이 tkinter에서 처리되고 있습니다. 클립 보드가 바뀌면 pywin32 바인딩은 클립 보드 감시 및 클립 보드 액세스를 수행합니다. 클립 보드가 pywin32 작업을 보는 방식에 관해서 내가 수집 한 것부터, pywin32에 윈도우의 hwnd 값을 제공하는 한 원하는 모든 작업을 할 수 있습니다. 나는 그 부분을하고 있으며 프로그램이 처음 시작할 때 작동합니다. 클립 보드가 바뀌면 작동하지 않는 것 같습니다.

프로그램이 실행되면 클립 보드를 잡고 검색 상자와 편집 상자에 넣습니다. 클립 보드가 수정되면 발사하고 싶은 이벤트가 시작됩니다 ... 프로그램이 시작될 때 완전히 작동했던 이벤트를 제외하고는 이제 수행해야 할 작업을 수행하는 대신 이상한 응답이 발생합니다. 클립 보드가 변경되면 클립 보드 내용을 표준 출력으로 인쇄 할 수 있지만 같은 데이터를 tkinter 위젯에 넣지는 않습니다. 그것은 클립 보드 변경 알림에 의해 해고 된 후 내 tkinter 위젯 중 하나와 상호 작용하기 시작하면 중단됩니다.

필자가 tkinter를 사용하는 프로그램에 사용했던 샘플 코드를 클립 보드에서 보는 것에 적응하지 못했던 pywin32 에티켓이있는 것처럼 느껴집니다. Tkinter는 스택 트레이스 나 에러 메시지를 생성하는 것을 좋아하지 않으며, pdb로 디버깅하려고 시도 할 때 무엇을 찾으려고하는지조차 알 수 없습니다.

여기에 코드입니다 : 그것은 도움이 될 수 있다면

#coding: utf-8 
#Clipboard watching cribbed from ## {{{ http://code.activestate.com/recipes/355593/ (r1) 

import pdb 
from Tkinter import * 
import win32clipboard 
import win32api 
import win32gui 
import win32con 
import win32clipboard 


def force_unicode(object, encoding="utf-8"): 
    if isinstance(object, basestring) and not isinstance(object, unicode): 
     object = unicode(object, encoding) 
    return object 

class Application(Frame): 
    def __init__(self, master=None): 
     self.master = master 
     Frame.__init__(self, master) 
     self.pack() 
     self.createWidgets() 

     self.hwnd = self.winfo_id() 
     self.nextWnd = None 
     self.first = True 
     self.oldWndProc = win32gui.SetWindowLong(self.hwnd, win32con.GWL_WNDPROC, self.MyWndProc) 
     try: 
      self.nextWnd = win32clipboard.SetClipboardViewer(self.hwnd) 
     except win32api.error: 
      if win32api.GetLastError() == 0: 
       # information that there is no other window in chain 
       pass 
      else: 
       raise 

     self.update_search_box() 
     self.word_search() 

    def word_search(self): 
     #pdb.set_trace() 
     term = self.searchbox.get() 
     self.resultsbox.insert(END, term) 

    def update_search_box(self): 
     clipboardtext = "" 
     if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_TEXT): 
      win32clipboard.OpenClipboard() 
      clipboardtext = win32clipboard.GetClipboardData() 
      win32clipboard.CloseClipboard() 

     if clipboardtext != "": 
      self.searchbox.delete(0,END) 
      clipboardtext = force_unicode(clipboardtext) 
      self.searchbox.insert(0, clipboardtext) 

    def createWidgets(self): 
     self.button = Button(self) 
     self.button["text"] = "Search" 
     self.button["command"] = self.word_search 

     self.searchbox = Entry(self) 
     self.resultsbox = Text(self) 

     #Pack everything down here for "easy" layout changes later 
     self.searchbox.pack() 
     self.button.pack() 
     self.resultsbox.pack() 

    def MyWndProc (self, hWnd, msg, wParam, lParam): 
     if msg == win32con.WM_CHANGECBCHAIN: 
      self.OnChangeCBChain(msg, wParam, lParam) 
     elif msg == win32con.WM_DRAWCLIPBOARD: 
      self.OnDrawClipboard(msg, wParam, lParam) 

     # Restore the old WndProc. Notice the use of win32api 
     # instead of win32gui here. This is to avoid an error due to 
     # not passing a callable object. 
     if msg == win32con.WM_DESTROY: 
      if self.nextWnd: 
       win32clipboard.ChangeClipboardChain (self.hwnd, self.nextWnd) 
      else: 
       win32clipboard.ChangeClipboardChain (self.hwnd, 0) 

      win32api.SetWindowLong(self.hwnd, win32con.GWL_WNDPROC, self.oldWndProc) 

     # Pass all messages (in this case, yours may be different) on 
     # to the original WndProc 
     return win32gui.CallWindowProc(self.oldWndProc, hWnd, msg, wParam, lParam) 

    def OnChangeCBChain (self, msg, wParam, lParam): 
     if self.nextWnd == wParam: 
      # repair the chain 
      self.nextWnd = lParam 
     if self.nextWnd: 
      # pass the message to the next window in chain 
      win32api.SendMessage (self.nextWnd, msg, wParam, lParam) 

    def OnDrawClipboard (self, msg, wParam, lParam): 
     if self.first: 
      self.first = False 
     else: 
      #print "changed" 
      self.word_search() 
      #self.word_search() 

     if self.nextWnd: 
      # pass the message to the next window in chain 
      win32api.SendMessage(self.nextWnd, msg, wParam, lParam) 


if __name__ == "__main__": 
    root = Tk() 
    app = Application(master=root) 
    app.mainloop() 
    root.destroy() 

답변

2

확실하지,하지만 난 당신이 Win32에서 이벤트 핸들러 내부에서 업데이트를 호출로 분해 가정 Tkinter를 그렇게하지 않을 수 있습니다.

대개 일반적인 비법은 after_idle() 콜백을 통해 업데이트를 지연시키는 것입니다. 나는 그 아마 일 것이라고 생각

def OnDrawClipboard (self, msg, wParam, lParam): 
    if self.first: 
     self.first = False 
    else: 
     #print "changed" 
     self.after_idle(self.word_search) 
     #self.word_search() 

    if self.nextWnd: 
     # pass the message to the next window in chain 
     win32api.SendMessage(self.nextWnd, msg, wParam, lParam) 
+1

을,하지만 난으로 업데이트를 트리거하는 메인 루프 일종의 폴링해야이 함께

def OnDrawClipboard (self, msg, wParam, lParam): if self.first: self.first = False else: #print "changed" self.word_search() #self.word_search() if self.nextWnd: # pass the message to the next window in chain win32api.SendMessage(self.nextWnd, msg, wParam, lParam) 

을 :

그래서 대체하려고 부울 변수는 다른 곳에 배치됩니다. 이 질문에 답변 해 주셔서 감사합니다. 응답이 없으면 오랜 시간이 지난 후에 전체 프로젝트를 wxPython으로 변환했습니다. 나는 wxPython을 그다지 좋아하지 않지만,이 작은 프로젝트에서는 완전히 채택하기가 두통에 지나지 않습니다. – Erlog

관련 문제