2013-02-04 20 views
12

Khi tôi gọiRuntimeError: chủ đề chính không phải là trong vòng lặp chính

self.client = ThreadedClient() 

trong chương trình Python, tôi nhận được lỗi

"RuntimeError: main thread is not in main loop"

tôi đã làm một số googling, nhưng tôi đang làm cho một lỗi nào đó ... Ai đó có thể giúp tôi không?

Full lỗi:

Exception in thread Thread-1: 
    Traceback (most recent call last): 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 530, in __bootstrap_inner 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 483, in run 
    File "/Users/Wim/Bird Swarm/bird_swarm.py", line 156, in workerGuiThread 
    self.root.after(200, self.workerGuiThread) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 501, in after 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1098, in _register 
    RuntimeError: main thread is not in main loop 

Lớp học:

class ThreadedClient(object): 

    def __init__(self): 
     self.queue = Queue.Queue() 
     self.gui = GuiPart(self.queue, self.endApplication) 
     self.root = self.gui.getRoot() 
     self.running = True 
     self.GuiThread = threading.Thread(target=self.workerGuiThread) 
     self.GuiThread.start() 

    def workerGuiThread(self): 
     while self.running: 
      self.root.after(200, self.workerGuiThread) 
      self.gui.processIncoming()  

    def endApplication(self): 
     self.running = False 

    def tc_TekenVogel(self,vogel): 
     self.queue.put(vogel) 

class GuiPart(object): 
    def __init__(self, queue, endCommand): 
     self.queue = queue 
     self.root = Tkinter.Tk() 
     Tkinter.Canvas(self.root,width=g_groottescherm,height=g_groottescherm).pack() 
     Tkinter.Button(self.root, text="Move 1 tick", command=self.doSomething).pack() 
     self.vogelcords = {} #register of bird and their corresponding coordinates 

    def getRoot(self): 
     return self.root 

    def doSomething(): 
     pass #button action 

    def processIncoming(self): 
     while self.queue.qsize(): 
      try: 
       msg = self.queue.get(0) 
       try: 
        vogel = msg 
        l = vogel.geeflocatie() 
        if self.vogelcords.has_key(vogel): 
         cirkel = self.vogelcords[vogel] 
         self.gcanvas.coords(cirkel,l.geefx()-g_groottevogel,l.geefy()-g_groottevogel,l.geefx()+g_groottevogel,l.geefy()+g_groottevogel)    
        else: 
         cirkel = self.gcanvas.create_oval(l.geefx()-g_groottevogel,l.geefy()-g_groottevogel,l.geefx()+g_groottevogel,l.geefy()+g_groottevogel,fill='red',outline='black',width=1) 
         self.vogelcords[vogel] = cirkel 
        self.gcanvas.update() 
       except: 
        print('Failed, was van het type %' % type(msg)) 
      except Queue.Empty: 
       pass 
+0

Từ traceback của bạn, có vẻ như bạn đang chạy 'workerGuiThread' từ chuỗi bạn đang tạo ở nơi khác, thay vì từ chuỗi chính của quá trình thực hiện. Tôi không phải là chuyên gia TK, nhưng lỗi này dường như gợi ý rằng điều này không được phép (bạn cần phải sử dụng chuỗi chính để gọi các hàm TK, như 'after'). – Blckknght

+0

Xem [câu hỏi này] (http://stackoverflow.com/questions/3567238/i-need-a-little-help-with-python-tkinter-and-threading), [câu trả lời này] (http: // stackoverflow .com/a/10556698/908494), vv để biết thêm chi tiết về việc sử dụng TkInter trong một chương trình đa luồng. Nhưng phiên bản ngắn là: Chỉ sử dụng nó trong chủ đề chính, thời gian. – abarnert

+0

Hey Blckknght. Vì tôi đang sử dụng mtTkinter. – user2040823

Trả lời

17

Bạn đang chạy vòng lặp GUI chính của bạn trong một thread bên cạnh các chủ đề chính. Bạn không thể làm điều này.

Các tài liệu được đề cập một cách dễ dàng ở một vài nơi mà Tkinter không hoàn toàn an toàn, nhưng theo như tôi biết, không bao giờ khá xuất hiện và nói rằng bạn chỉ có thể nói chuyện với Tk từ chuỗi chính. Lý do là sự thật hơi phức tạp. Bản thân Tkinter chỉ an toàn nhưng khó sử dụng theo cách đa luồng. Gần nhất với tài liệu chính thức về vấn đề này có vẻ là this page:

Q. Is there an alternative to Tkinter that is thread safe?

Tkinter?

Just run all UI code in the main thread, and let the writers write to a Queue object…

(Mẫu mã nhất định là không lớn, nhưng nó đủ để tìm ra những gì họ đang đề xuất và làm những việc đúng cách.)

Có thực tế một giải pháp thay thế an toàn cho Tkinter, mtTkinter. Và tài liệu của nó thực sự giải thích tình hình khá tốt:

Although Tkinter is technically thread-safe (assuming Tk is built with --enable-threads), practically speaking there are still problems when used in multithreaded Python applications. The problems stem from the fact that the _tkinter module attempts to gain control of the main thread via a polling technique when processing calls from other threads.

Tôi tin rằng đây là chính xác những gì bạn đang thấy: Mã Tkinter của bạn trong Thread-1 đang cố gắng để nhìn trộm vào các chủ đề chính để tìm số vòng lặp chính, và nó không có ở đó.

Vì vậy, đây là một số lựa chọn:

  • Hãy làm những gì các tài liệu Tkinter giới thiệu và sử dụng Tkinter từ các chủ đề chính. Có thể bằng cách di chuyển mã chuỗi chính hiện tại của bạn thành một chuỗi công nhân.
  • Nếu bạn đang sử dụng một số thư viện khác muốn tiếp quản chuỗi chính (ví dụ: twisted), nó có thể có cách tích hợp với Tkinter, trong trường hợp này bạn nên sử dụng.
  • Sử dụng mkTkinter để khắc phục sự cố.

Ngoài ra, mặc dù tôi không tìm thấy bất kỳ trùng lặp chính xác nào của câu hỏi này, có một số câu hỏi liên quan đến SO. Xem this question, this answer và nhiều thông tin khác để biết thêm thông tin.

+0

Hey abarnert. Cảm ơn câu trả lời của bạn. Tôi đã sử dụng cho các tùy chọn với mtTkinter. Mã của tôi đang chạy (không có lỗi tôi có ý nghĩa). Nhưng tôi không thể nhìn thấy vải ... Trong quá trình ghi nhật ký, tôi thấy chương trình đang hoạt động ... mà không có hình ảnh. Bạn không thể thấy mã @ https://github.com/wimhendrickx/Flocking/blob/master/bird_swarm.py. Cảm ơn trước. – user2040823

+0

@ user2040823: Tại sao tôi không thể thấy mã, có phải là văn bản màu trắng trên nền trắng không? :) Dù sao, tôi sẽ tải về nó và hãy xem. – abarnert

+0

@ user2040823: OK, có nhiều vấn đề cơ bản ở đây. Đầu tiên, bạn không gọi 'root.mainloop()' ở bất cứ đâu. Thứ hai, bạn có các phương thức như 'doSomething' không lấy' self' (và không phải 'staticmethod'). Thứ ba, trình xử lý sự kiện 'Tkinter' của bạn không tham số' event'. Tôi nghĩ rằng bạn cần phải làm việc thông qua một hướng dẫn Tkinter cơ bản trước khi bạn cố gắng xây dựng một cái gì đó phức tạp xung quanh nó và/hoặc sử dụng mtTkinter. Nếu bạn có bất kỳ câu hỏi cụ thể nào mà bạn không thể tìm thấy câu trả lời, hãy tạo một câu hỏi mới, nhưng tôi không thể dạy cho bạn những kiến ​​thức cơ bản về Tkinter trong các bình luận SO. – abarnert

Các vấn đề liên quan