2013-11-23 4 views
2

tkinter 응용 프로그램 (기본 스레드로 실행)이 있습니다. 새 최상위 창을 엽니 다. 테스트의 로그 창 인쇄 결과입니다 (테스트는 셀레늄 webdriver). 이 대화 상자는 모든 테스트의 호출자이기도합니다.Tkinter에서 스레드를 실행하고 완료 될 때까지 기다리십시오.

그래서 최상위 레벨로 전체 응용 프로그램을위한 하나의 창이 있습니다. 테스트를 실행하고 테스트가 완료 될 때까지 기다렸다가 결과를 인쇄 한 다음 다른 테스트 단위에 대해 동일한 작업을 수행합니다. . 하지만 테스트를 진행하는 동안 창을 멈추게하고 싶지는 않습니다.

나는 스레드를 사용하려했지만 분명히 그렇게 할 수있다. 이 경우 테스트가 완료 될 때까지 대화 상자가 시작되지 않습니다.

다음은 대화 상자의 코드입니다.

testDialog = TestDialog(self.parent, self._webtester, url) 

어떤 조언을 주셔서 감사합니다 :

class TestDialog(tkinter.Toplevel): 

    def __init__(self, parent, tester, url): 
     super().__init__(parent)   
     self.parent = parent 
     self.webtester = tester; 

     self.__initComponents() 

     self.run(url)    

     self.wait_window(self) 

    def __initComponents(self): 
     self.transient(self.parent) 

     frame = tkinter.Frame(self) 

     self._tarea = tkinter.Text(frame, state='disabled',wrap='none', width=55, height=25) 

     vsb = tkinter.Scrollbar(frame, orient=tkinter.VERTICAL, command=self._tarea.yview) 
     self._tarea.configure(yscrollcommand=vsb.set) 


     self._tarea.grid(row=1, column=0, columnspan=4, sticky="NSEW", padx=3, pady=3) 
     vsb.grid(row=1, column=4, sticky='NS',pady=3) 
     frame.grid(row=0, column=0, sticky=tkinter.NSEW) 

     frame.columnconfigure(0, weight=2) 
     frame.rowconfigure(1, weight=1) 

     window = self.winfo_toplevel() 
     window.columnconfigure(0, weight=1) 
     window.rowconfigure(0, weight=1) 

     self.bind("<Escape>", self.close) 

     self.protocol("WM_DELETE_WINDOW", self.close) 
     self.grab_set() 

    def appendLine(self, msg): 
     self._tarea['state'] = 'normal' 
     self._tarea.insert("end", msg+'\n') 
     self._tarea['state'] = 'disabled' 

    def run(self, url): 

     self.appendLine("Runneing test #1...") 

     try: 
      thr = threading.Thread(target=self.webtester.urlopen, args=(url,)) 
      thr.start() 
     except: 
      pass 

     thr.join() 

     self.webtester.urlopen(url) 

     self.appendLine("Running test #2")   
     try: 
      thr = threading.Thread(target=self.webtester.test2) 
      thr.start() 
     except: 
      pass   

    def close(self, event=None): 
     self.parent.setBackgroundScheme(DataTreeView.S_DEFAULT) 
     self.parent.focus_set() 
     self.destroy() 

이 대화는 단순히 의해 부모 창에서 열립니다.

답변

3

GUI가 멈추는 것을 막으려면 self.run()을 빨리 종료해야합니다. 그것은, 스레드를 생성 스레드를 시작해야, 다음 종료 :

import Queue 
sentinel = object() 
root = tkinter.Tk() 

... 
def run(self, url): 
    outqueue = Queue.Queue() 
    thr = threading.Thread(target=self.run_tests, args=(url, outqueue)) 
    thr.start() 
    root.after(250, self.update, outqueue) 

지금이 스레드 실행이 오랜 시간 동안 실행할 수있는 기능 :

def run_tests(self, url, outqueue): 
    outqueue.put("Running test #1...") 
    self.webtester.urlopen(url) 
    outqueue.put("Running test #2")   
    self.webtester.test2() 
    outqueue.put(sentinel) 

그러나 Tkinter를 기대하기 때문에 모든 GUI가 호출 단일 스레드에서 시작된 경우이 생성 된 스레드는 GUI 호출을해서는 안됩니다. 는 GUI와 상호 작용하려면, 당신은 Queue.Queue을 통해 (예 : 상태 업데이트 메시지로) 출력을 전송하고 동시에 주요 Tkinter를 스레드 (root.after 호출을 통해) 주기적으로이 Queue.Queue을 모니터링 할 수 있습니다 : 나는했습니다

def update(self, outqueue): 
    try: 
     msg = outqueue.get_nowait() 
     if msg is not sentinel: 
      self.appendLine(msg) 
      root.after(250, self.update, outqueue) 
     else: 
      # By not calling root.after here, we allow update to 
      # truly end 
      pass 
    except Queue.Empty: 
     root.after(250, self.update, outqueue) 
+0

혼자서도 아주 비슷한 것을 알아 냈지만 솔루션이 더 우아하고 문제를 이해하는 데 도움이되었습니다. 감사합니다! – dakov

관련 문제