Подтвердить что ты не робот

RuntimeError: основной поток не находится в основном цикле

Когда я звоню

self.client = ThreadedClient() 

в моей программе Python, я получаю сообщение об ошибке

"RuntimeError: основной поток не находится в основном цикле"

Я уже сделал несколько поисковых запросов, но я как-то делаю ошибку... Может кто-то, пожалуйста, помогите мне?

Полная ошибка:

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

Классы:

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
4b9b3361

Ответ 1

Вы используете свой основной цикл GUI в потоке, кроме основного потока. Вы не можете этого сделать.

Документы упоминаются в нескольких местах, в которых Tkinter не совсем потокобезопасен, но, насколько я знаю, никогда не выходят и говорят, что вы можете разговаривать только с Tk из основного потока. Причина в том, что правда несколько сложна. Сам Tkinter является потокобезопасным, но его трудно использовать многопоточным способом. Самое близкое к официальной документации по этому вопросу выглядит эта страница:

Q. Есть ли альтернатива Tkinter, которая является потокобезопасной?

Tkinter?

Просто запустите весь код пользовательского интерфейса в основном потоке и позвольте авторам писать в объект Queue...

(Приведенный пример кода невелик, но достаточно, чтобы понять, что они предлагают и что-то делать правильно.)

На самом деле существует поточно-безопасная альтернатива Tkinter, mtTkinter. И его документы действительно хорошо объясняют ситуацию:

Хотя Tkinter технически потокобезопасен (предполагается, что Tk построен с --enable-threads), практически все еще существуют проблемы при использовании в многопоточных приложениях Python. Проблемы связаны с тем, что модуль _tkinter пытается получить контроль над основным потоком с помощью метода опроса при обработке вызовов из других потоков.

Я считаю, что это именно то, что вы видите: ваш код Tkinter в Thread-1 пытается заглянуть в основной поток, чтобы найти основной цикл, и он не существует.

Итак, вот несколько вариантов:

  • Сделайте то, что рекомендуют документы Tkinter и используйте TkInter из основного потока. Возможно, переместив текущий текущий код потока в рабочий поток.
  • Если вы используете другую библиотеку, которая хочет взять основной поток (например, twisted), у него может быть способ интеграции с Tkinter, и в этом случае вы должны использовать это.
  • Используйте mkTkinter для решения проблемы.

Кроме того, хотя я не нашел ни одного точного дубликата этого вопроса, на SO есть ряд связанных вопросов. См. этот вопрос, этот ответ и многое другое для получения дополнительной информации.