运行时错误:主线程不在主循环中 [英] RuntimeError: main thread is not in main loop

查看:29
本文介绍了运行时错误:主线程不在主循环中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我打电话时

self.client = ThreadedClient() 

在我的 Python 程序中,我收到错误

in my Python program, I get the error

运行时错误:主线程不在主循环中"

"RuntimeError: main thread is not in main loop"

我已经做了一些谷歌搜索,但不知何故我犯了一个错误......有人可以帮我吗?

I have already done some googling, but I am making an error somehow ... Can someone please help me out?

完全错误:

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

推荐答案

您正在主线程之外的一个线程中运行主 GUI 循环.你不能这样做.

You're running your main GUI loop in a thread besides the main thread. You cannot do this.

文档在一些地方随意提到 Tkinter 不是完全线程安全的,但据我所知,从来没有站出来说你只能从主线程与 Tk 对话.原因是真相有些复杂.Tkinter 本身 是线程安全的,但它很难以多线程方式使用.最接近官方文档的似乎是这个页面:

The docs mention offhandedly in a few places that Tkinter is not quite thread safe, but as far as I know, never quite come out and say that you can only talk to Tk from the main thread. The reason is that the truth is somewhat complicated. Tkinter itself is thread-safe, but it's hard to use in a multithreaded way. The closest to official documentation on this seems to be this page:

问.是否有线程安全的 Tkinter 替代方案?

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

Tkinter?

只需在主线程中运行所有 UI 代码,然后让编写者写入 Queue 对象......

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

(给出的示例代码不是很好,但足以弄清楚他们的建议并正确地做事.)

(The sample code given isn't great, but it's enough to figure out what they're suggesting and do things properly.)

实际上是 Tkinter 的线程安全替代品,mtTkinter.它的文档实际上很好地解释了这种情况:

There actually is a thread-safe alternative to Tkinter, mtTkinter. And its docs actually explain the situation pretty well:

虽然 Tkinter 在技术上是线程安全的(假设 Tk 是使用 --enable-threads 构建的),但实际上在多线程 Python 应用程序中使用时仍然存在问题.问题源于以下事实:_tkinter 模块在处理来自其他线程的调用时试图通过轮询技术获得对主线程的控制.

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.

我相信这正是您所看到的:您在 Thread-1 中的 Tkinter 代码试图窥视主线程以找到主循环,但它并不存在.

I believe this is exactly what you're seeing: your Tkinter code in Thread-1 is trying to peek into the main thread to find the main loop, and it's not there.

所以,这里有一些选择:

So, here are some options:

  • 按照 Tkinter 文档的建议进行操作,并在主线程中使用 TkInter.可能通过将您当前的主线程代码移动到工作线程中.
  • 如果您正在使用其他一些想要接管主线程的库(例如,twisted),它可能有一种与 Tkinter 集成的方法,在这种情况下,您应该使用它.
  • 使用mkTkinter来解决问题.
  • Do what the Tkinter docs recommend and use TkInter from the main thread. Possibly by moving your current main thread code into a worker thread.
  • If you're using some other library that wants to take over the main thread (e.g., twisted), it may have a way to integrate with Tkinter, in which case you should use that.
  • Use mkTkinter to solve the problem.

另外,虽然我没有发现这个问题的任何完全重复,但有一些关于 SO 的相关问题.参见这个问题这个答案,以及更多信息.

Also, while I didn't find any exact duplicates of this question, there are a number of related questions on SO. See this question, this answer, and many more for more information.

这篇关于运行时错误:主线程不在主循环中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆