2012-12-06 3 views
0

그래서 정보를 입력하고 입력 필드를 지우고 새 입력 필드를 추가하는 GUI를 작성하려고합니다. 그러나 grid_remove를 통해 루트에서 프레임을 지우려고하면 응용 프로그램이 정지합니다. 관련 코드는 다음과 같습니다.Tkinter Freeze on grid_remove

import tkinter 
from threading import Thread 

class PinGui(tkinter.Frame): 
    def __init__(self, client): 
     self.client = client 
     self.root = client.root 
     self.add_pin = client.add_pin 
     self.end = client.end 
     tkinter.Frame.__init__(self, self.root) 
     self.grid_widgets() 
     self.grid_buttons() 
     self.bind_keys() 
     self.grid(padx=32, pady=32) 

    def grid_buttons(self, b1='Add', b2='Reset', b3='Quit'): 
     self.addButton = tkinter.Button(self, text=b1, command=self.validate) 
     self.resetButton = tkinter.Button(self, text=b2, command=self.reset) 
     self.quitButton = tkinter.Button(self, text=b3, command=self.end) 
     self.buttons = [self.addButton, self.resetButton, self.quitButton] 
     for i in range(3): self.buttons[i].grid(row=i, column=11) 

    def grid_widgets(self): 
     widths = [3,3,4,4,6] 
     self.pin_vars = [] 
     self.pin_fields = [] 
     for i in range(5): 
      self.pin_vars.append(tkinter.StringVar()) 
      self.pin_fields.append(
       tkinter.Entry(self,width=widths[i], textvariable=self.pin_vars[i]) 
       ) 
      self.pin_fields[i].grid(row=0, column=2*i, padx=3) 
     self.pin_fields[0].focus_set() 

    def bind_keys(self): 
     self.root.bind_all("<Return>", self.validate) 
     self.root.bind_all("<Escape>", self.end) 

    def validate(self, args=None): 
     self.client.pin = [] 
     for field in self.pin_fields: 
      self.client.pin.append(field.get()) 
     Thread(target=self.add_pin).start() 

    def ungrid(self): 
     for field in self.pin_fields: field.grid_remove() 
     for button in self.buttons: button.grid_remove() 
     self.display.grid_remove() 

그리고는 :

class PinClient: 
    def __init__(self): 
     self.root = tkinter.Tk() 
     self.gui = PinGui(self) 
     self.pins = [] 

    def add_pin(self): 
     self.gui.reset() 
     if 'display' in self.__dict__: 
      self.pins.append(self.pin) 
      self.display.add_pin(self.pin) 
      self.ping("Enter PIN for Comp %s:" % len(self.display.col1)) 
      if len(self.display.col1) > 5: 
       self.end() # THIS IS WHERE IT FREEZES 
     else: 
      self.subject = self.pin 
      self.display = Display(self.root, self.pin) 
      self.display.grid(row=1, padx=32, pady=32) 
      self.ping("Enter PIN for Comp 1:") 

    def ping(self, msg): 
     self.gui.d_var.set(msg) 

    def end(self, args=None): 
     self.gui.ungrid() 

class Display(tkinter.Frame): 
    def __init__(self, master, pin): 
     tkinter.Frame.__init__(self, master) 
     self.pin = pin 
     self.col1 = [] 
     self.col2 = [] 
     self.col1.append(tkinter.Label(self, text="Subject:")) 
     self.col2.append(tkinter.Label(self, text=self.pin)) 
     self.grid_widgets() 

    def grid_widgets(self): 
     self.ungrid() 
     for i in range(len(self.col1)): 
      self.col1[i].grid(row=i, column=0) 
      self.col2[i].grid(row=i, column=1) 

    def ungrid(self): 
     for i in range(len(self.col1)): 
      self.col1[i].grid_remove() 
      self.col2[i].grid_remove() 

    def add_pin(self, pin): 
     self.col1.append(tkinter.Label(self, text="Comp %s:" % len(self.col1))) 
     self.col2.append(tkinter.Label(self, text=pin)) 
     i = len(self.col1) 
     self.col1[i-1].grid(row=i, column=0) 
     self.col2[i-1].grid(row=i, column=1) 

어떻게 든 스레딩과 관련이있을 것 같다,하지만 난이 얼어 야 할 이유를 찾을 수 없어. 어떤 도움이라도 대단히 감사합니다!

답변

0

Tkinter는 스레드로부터 안전하지 않습니다. GUI 객체에 닿는 주 스레드 이외의 스레드에서 작업을 수행하면 예기치 않은 결과가 발생합니다. 작업자 스레드에서 위젯에 액세스하려고하기 때문에 거의 확실하게 문제를 일으키는 스레딩입니다.

+0

실제로이 문제는 스레드 스레딩을 시도하기 전에 발생했습니다. 진짜 문제는 올바른 스레드 (즉, 메인 루프)에 있지 않다는 것입니다. 나는 ungrid 명령을 GUI의 대기열에 보냄으로써 문제를 해결했으며, GUI의 대기 행렬에서 명령을 실행합니다. –