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
Ответы
Ответ 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 есть ряд связанных вопросов. См. этот вопрос, этот ответ и многое другое для получения дополнительной информации.