2015-01-26 2 views
0

내가 그 위의 코드가 있다는 것입니다으로 포트 27파이썬 : Tkinter를 변화의 응용 프로그램 아이콘이

def main(): 
    t = Test() 
    t.go() 
    try: 
     join_threads(t.threads) 
    except KeyboardInterrupt: 
     print "\nKeyboardInterrupt catched." 
     print "Terminate main thread." 
     print "If only daemonic threads are left, terminate whole program." 

class Test(object): 

    def __init__(self): 
     self.running = True 
     self.threads = [] 
     self.root=Tk() 
     self.Rval = IntVar() 
     self.Rval.set(2) 
     self.root.title("RFID EM LOCK CONTROLLER") 
     self.variable=StringVar() 
     self.variable2=StringVar() 
     self.var2=StringVar() 
     self.var3=StringVar() 
     self.i=0 
     self.root.resizable(0,0) 
     self.your_label=Label(self.root,textvariable=self.variable,width=40,height=5,bg="Black",fg="Green") 
     self.lframe = Frame(self.root,width=300,height=200,padx=0) 
     self.lframe.pack() 
     self.root.wm_iconbitmap(bitmap = "icon.ico") 

    def foo(self): 
     ser=serial.Serial("COM27",9600) 
     while(self.running): 
      self.var2= ser.readline() 
      v = self.var2[0:8]; 
      print v 
      if self.Isexist(v): 
       ser.write('A') 
       self.var2="Valid Card\n"+"Card Number: "+v; 
      else: 
       ser.write('B') 
       self.var2="InValid Card\n"+"Card Number: "+v; 
    def grid(self): 
     self.your_label.pack() 

    def update_label(self): 
     self.i=self.i+1 
     self.variable.set(str(self.var2)) 
     self.variable2.set(str(self.var2)) 
     self.root.after(20,self.update_label)      
    def get_user_input(self): 
     self.grid() 
     self.root.after(20,self.update_label) 
     self.root.mainloop() 

    def go(self): 
     t1 = threading.Thread(target=self.foo) 
     t2 = threading.Thread(target=self.get_user_input) 
     # Make threads daemonic, i.e. terminate them when main thread 
     # terminates. From: http://stackoverflow.com/a/3788243/145400 
     t1.daemon = True 
     t2.daemon = True 
     t1.start() 
     t2.start() 
     self.threads.append(t1) 
     self.threads.append(t2) 


def join_threads(threads): 
    """ 
    Join threads in interruptable fashion. 
    From http://stackoverflow.com/a/9790882/145400 
    """ 
    for t in threads: 
     while t.isAlive(): 
      t.join(5) 

if __name__ == "__main__": 
    main() 

에 아두 이노 입력에 대한 문제를 확인에 유지하기 때문에 스레드와 Tkinter를 .I 스레드를 사용 사용하여 GUI 프로그램을 작성 중단 윈도우 8.1에서 prox64에 self.root.wm_iconbitmap(bitmap = "icon.ico")을 사용하여 응용 프로그램 아이콘을 설정하면 멈 춥니 다. 파이썬 2.7 tkinter 함께 사용하고 있습니다. 응용 프로그램 아이콘없이 작동합니다.

이 문제를 해결하는 방법은 무엇입니까?

답변

2

tkinter은 주 스레드가 아닌 다른 스레드에서 실행되는 것이 좋습니다. 두 개의 백그라운드 스레드를 시작합니다. self.foo 보이 OK - 어떤 tkinter 전화도 걸리지 않습니다. 그러나 self.get_user_input 전화는 tkinter이고 pack, aftermainloop입니다. 두 가지 결과가 예상됩니다. 첫째, 자동으로 Bryan Oakley을 소환합니다. 여기에 누가 연기가 나고 여기에 나타나며이를 수행 할 수 없다고 알려줍니다. 둘째로, 산발적이거나 그렇게 산발적이지 않은 정지 및 충돌을 포함하여 프로그램의 정의되지 않은 동작이 발생합니다. 이것이 정확히 어떻게 wm_iconbitmap과 상호 작용할지 모르겠지만 정의되지 않은 동작은 모든 이유를 무시할 수 있으며 tkinter 호출을 포함하는 백그라운드 스레드는 기껏해야 시한 폭탄입니다.

이미 사용중인 after 메서드는 실제로 tkinter 응용 프로그램에서 배경 스레드가 필요하지 않게하는 좋은 방법입니다. after에 대한 실제 호출은 즉시 반환되므로 주 스레드에서 사용하기 쉽고 작업은 안전한 tkinter 관리 방법으로 백그라운드에서 수행되도록 예약됩니다.

다음은 self.root.mainloop()을 호출하는 대신 GUI의 주요 업데이트 루프를 백그라운드에서 수행하는 방법입니다. 다만이 방법을 정의한 다음 메인 스레드에서 한 번 전화 --- 즉시 (거의) 반환하고 백그라운드에서 진행 자체를 유지합니다 :

def background_updateloop(self): 
    self.root.update() 
    self.afterID_updateloop = self.root.after(100, self.background_updateloop) 

그것을 중지하려면 self.root.after_cancel(self.afterID_updateloop)를 호출합니다.

+0

아직도 ... 방대한 @Bryan 오클리가 나타나 내 답변을 철거 가지고, 친구의 날을 도움 과거에. 또한 메인 프레임 외부에서 '시간이 너무 짧아서'.after를 호출하면 즉시 발생합니다. 문제를 해결하기 위해 일반적으로 좋은 방법입니다. 또는 적어도 발견했습니다. @sonu kumar는'.after'가 아닌 다른 tkinter 호출을 별도의 메소드로 옮기고'.after'로 호출 할 수 있습니다. –

+0

@BenjaminJamesDrury 나는 당신이하는 말을 이해할 수 없었다. 더 설명해 주시겠습니까? –

+1

물론, 나는 그것을 완전히 대답 할 것이다. –

0

이미 언급했듯이 별도의 스레드에서 모든 종류의 tkinter 메서드를 호출하면 문제가 발생하지만 .after을 사용하여 정렬 할 수 있습니다.

.after은 tkinter가 표시하는 모든 것을 직접 변경시키지 않지만 처리 할 수있는 주 스레드에서 발생하는 이벤트를 대기열에 넣습니다. .after을 작은 timescale (예 : 100 밀리 초)로 호출하고 원하는 tkinter 호출을 포함하는 메소드로 지시하면 안전하게 주 스레드 외부에서 tkinter 호출을 만들 수 있습니다.이 호출은 주 스레드에서 거의 즉시 실행됩니다 .

내 의미를 명확하게 설명하지 않은 경우 아이콘 변경 줄을 예로 들어 코드를 아래에 넣습니다. 처음, 아이콘을 변경으로 변경하기 위해 호출

def change_icon(self): 
    self.root.wm_iconbitmap(bitmap = "icon.ico") 

다음 : 많은 경우에

self.root.after(100, self.change_icon) 
+1

백그라운드에서 아이콘을 변경해야한다고 생각하지 않습니다. 변경 아이콘은 한 번만 수행해야하며 동기식으로 수행 할 수 있습니다. 아이콘 호출에 대한 크래시의 명백한 의존성은 아마 무작위 일 것입니다. 주요 문제를 먼저 수정하십시오. 즉, 백그라운드 스레드에서 백그라운드 스레드 및 기존 재귀 호출을 가져 와서 아이콘이 더 이상 차이를 만들지 여부를 확인하십시오. 내 생각에는 그렇지 않습니다. – jez

+0

네가 거의 틀림없이 네가 거의 확실하다. 처음에는 대답을 게시 할 시간이 제한되어있어 아이콘을 예제로 사용하는 것이 더 간단했다. –

관련 문제