当我打电话
self.client = ThreadedClient()
在我的Python程序中,我得到了错误
"运行时错误:主线程不在主循环中"
我已经做了一些谷歌搜索,但我正在犯一个错误不知何故...有人能帮我吗?
完整错误:
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
9条答案
按热度按时间vsaztqbk1#
您正在主线程之外的线程中运行主GUI循环。您不能这样做。
文档中有几处提到Tkinter不是线程安全的,但据我所知,从来没有明确说过你只能从主线程与Tk对话。原因是事实有些复杂。Tkinter本身是线程安全的,但很难以多线程的方式使用。在这方面最接近官方文档的似乎是this page:
问:是否有线程安全的Tkinter替代品?
金特?
只需在主线程中运行所有UI代码,并让编写器写入一个Queue对象...
(The给出的示例代码不是很好,但足以理解他们的建议并正确地执行操作。)
事实上,有一个线程安全的替代品mtTkinter可以替代Tkinter,它的文档很好地解释了这种情况:
尽管Tkinter在技术上是线程安全的(假设Tk是用--enable-threads构建的),但实际上在多线程Python应用程序中使用时仍然存在一些问题,这些问题源于_tkinter模块在处理来自其他线程的调用时试图通过轮询技术获得主线程的控制权。
我相信这正是你所看到的:Thread-1中的Tkinter代码试图窥视主线程以找到主循环,但它不在那里。
所以,这里有一些选择:
twisted
),那么它可能有办法与Tkinter集成,在这种情况下,您应该使用它。mkTkinter
解决该问题。此外,虽然我没有找到任何与此问题完全相同的问题,但在SO上有许多相关的问题。有关详细信息,请参阅this question、this answer等。
yhqotfr82#
我知道这有点晚了,但是我将线程设置为守护进程,并且没有引发异常:
p1iqtdky3#
我找到了一个解决的方法。它可能看起来像一个笑话,但你应该加上
v1uwarro4#
由于这一切确实帮助了我的问题,但没有完全解决它,这里是一个额外的事情要记住:
在我的例子中,我开始在许多线程中导入pyplot库并在那里使用它。在将所有库调用移到我的主线程后,我仍然得到那个错误。
我确实通过删除其他线程使用的其他文件中该库的所有import语句来消除它。即使他们没有使用该库,也会导致同样的错误。
eblbsuwk5#
也许这个例子能帮上忙。
2ekbmq326#
在结尾写上:
当然,如果
Tk
对象不是root
,则应该使用Tk
对象的名称来代替root
。fnvucqvd7#
你不能从另一个线程修改你的主GIU你需要发送事件到主GUI以避免异常使用window. write_event_value代替,这个方法允许你从你的线程发送事件你也可以看看这个:窗口.执行长时间操作
0kjbasz68#
我知道这个问题很久以前就有人问了,但我想告诉你我是如何解决这个问题的。在我的例子中,我有一个通过串行端口发送和接收消息的程序,并使用TKinter库。
如果我这样做:
当一个线程试图访问一个tkinter函数时,代码会崩溃。但是,如果我这样做:
所有的线程都正常执行。希望这对某人有帮助。
mm9b1k5b9#
安装tkinter的改进版本可以解决这个问题。不需要修改你的代码。你只需要做以下事情:管道3安装mtTkinter
然后在代码中添加以下内容:从mttkinter导入mtTkinter作为tk