简体   繁体   English

RuntimeError:主线程不在主循环中

[英]RuntimeError: main thread is not in main loop

When I call当我打电话

self.client = ThreadedClient() 

in my Python program, I get the error在我的 Python 程序中,出现错误

"RuntimeError: main thread is not in main loop" “RuntimeError:主线程不在主循环中”

I have already done some googling, but I am making an error somehow... Can someone please help me out?我已经做了一些谷歌搜索,但不知何故我犯了一个错误......有人可以帮我吗?

Full error:完整错误:

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

Classes:班级:

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

You're running your main GUI loop in a thread besides the main thread.您正在主线程之外的线程中运行主 GUI 循环。 You cannot do this.你不可以做这个。

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.文档在一些地方不经意地提到 Tkinter 不是完全线程安全的,但据我所知,从来没有站出来说你只能从主线程与 Tk 对话。 The reason is that the truth is somewhat complicated.原因是真相有些复杂。 Tkinter itself is thread-safe, but it's hard to use in a multithreaded way. Tkinter 本身线程安全的,但很难以多线程方式使用。 The closest to official documentation on this seems to be this page :最接近官方文档的似乎是这个页面

Q. Is there an alternative to Tkinter that is thread safe?问:是否有线程安全的 Tkinter 替代方案?

Tkinter?特金特?

Just run all UI code in the main thread, and let the writers write to a Queue object…只需在主线程中运行所有 UI 代码,然后让编写者写入 Queue 对象……

(The sample code given isn't great, but it's enough to figure out what they're suggesting and do things properly.) (给出的示例代码不是很好,但足以弄清楚他们的建议并正确地做事。)

There actually is a thread-safe alternative to Tkinter, mtTkinter .实际上一个线程安全的替代 Tkinter, mtTkinter And its docs actually explain the situation pretty well:它的文档实际上很好地解释了这种情况:

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.尽管 Tkinter 在技术上是线程安全的(假设 Tk 是使用 --enable-threads 构建的),但实际上在多线程 Python 应用程序中使用时仍然存在问题。 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.问题源于这样一个事实,即 _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.我相信这正是您所看到的:您在 Thread-1 中的 Tkinter 代码试图窥视主线程以找到主循环,但它并不存在。

So, here are some options:所以,这里有一些选择:

  • Do what the Tkinter docs recommend and use TkInter from the main thread.执行 Tkinter 文档的建议并从主线程使用 TkInter。 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 (eg, twisted ), it may have a way to integrate with Tkinter, in which case you should use that.如果您正在使用其他一些想要接管主线程的库(例如, twisted ),它可能有一种与 Tkinter 集成的方法,在这种情况下,您应该使用它。
  • Use mkTkinter to solve the problem.使用mkTkinter解决问题。

Also, while I didn't find any exact duplicates of this question, there are a number of related questions on SO.另外,虽然我没有发现这个问题的任何完全重复,但有一些关于 SO 的相关问题。 See this question , this answer , and many more for more information.请参阅此问题此答案以及更多信息以获取更多信息。

I know this is late, but I set my thread to a Daemon, and no exception was raised:我知道这已经晚了,但是我将线程设置为守护进程,并且没有引发异常:

t = threading.Thread(target=your_func)
t.setDaemon(True)
t.start()

I found a way to solve it.我找到了解决它的方法。 it might look like a joke but you just should add它可能看起来像一个笑话,但你应该添加

plt.switch_backend('agg')

Since all this did help my problem but did not solve it completely here is an additional thing to keep in mind:由于所有这些确实帮助了我的问题,但并没有完全解决它,因此需要记住的另一件事是:

In my case I started off importing the pyplot library in many threads and using it there.就我而言,我开始在许多线程中导入 pyplot 库并在那里使用它。 After moving all the library calls to my main thread I still got that error.将所有库调用移动到我的主线程后,我仍然遇到该错误。

I did get rid of it by removing all import statements of that library in other files used in other threads.我确实通过删除其他线程中使用的其他文件中该库的所有导入语句来摆脱它。 Even if they did not use the library the same error was caused by it.即使他们没有使用该库,也会导致同样的错误。

from tkinter import *
from threading import Thread
from time import sleep
from random import randint

class GUI():

    def __init__(self):
        self.root = Tk()
        self.root.geometry("200x200")

        self.btn = Button(self.root,text="lauch")
        self.btn.pack(expand=True)

        self.btn.config(command=self.action)

    def run(self):
        self.root.mainloop()

    def add(self,string,buffer):
        while  self.txt:
            msg = str(randint(1,100))+string+"\n"
            self.txt.insert(END,msg)
            sleep(0.5)

    def reset_lbl(self):
        self.txt = None
        self.second.destroy()

    def action(self):
        self.second = Toplevel()
        self.second.geometry("100x100")
        self.txt = Text(self.second)
        self.txt.pack(expand=True,fill="both")

        self.t = Thread(target=self.add,args=("new",None))
        self.t.setDaemon(True)
        self.t.start()

        self.second.protocol("WM_DELETE_WINDOW",self.reset_lbl)

a = GUI()
a.run()

maybe this example would help someone.也许这个例子会对某人有所帮助。

You cannot modify your main GIU from another thread you need to send event to the main GUI in order to avoid exceptions Use window.write_event_value instead, this method allows you to send events from your threads you can take a look a this too: window.perform_long_operation您不能从另一个线程修改您的主 GIU,您需要将事件发送到主 GUI 以避免异常 请改用 window.write_event_value,此方法允许您从您的线程发送事件,您也可以看看这个:window。执行长操作

Write it at the end:写在最后:

root.mainloop()

Of course, in place of root should be the name of your Tk object if it is not root .当然,如果不是root ,则代替root应该是您的Tk对象的名称。

I know this question was asked a long time ago, but I wanted to tell you how I solved it.我知道很久以前就有人问过这个问题,但我想告诉你我是如何解决它的。 In my case, I have a program that sends and receives messages through the serial port and uses the TKinter library.在我的例子中,我有一个通过串行端口发送和接收消息并使用 TKinter 库的程序。

If I do:如果我做:

while (True):
    #more code here
    window.update_idletasks()
    window.update()

The code crashes when a thread tries to access a tkinter function. But, if I do this:当线程尝试访问 tkinter function 时代码崩溃。但是,如果我这样做:

window.mainloop()

All the threads execute normaly.所有线程都正常执行。 Hope this helps someone.希望这对某人有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Matplotlib 和 :RuntimeError: 主线程不在主循环中: - Matplotlib and :RuntimeError: main thread is not in main loop: (Python tkinter):RuntimeError:主线程不在主循环中 - (Python tkinter): RuntimeError: main thread is not in main loop kochat in use RuntimeError: 主线程不在主循环中 - kochat in use RuntimeError: main thread is not in main loop PySimpleGUI。 运行时错误:主线程不在主循环中 - PySimpleGUI. RuntimeError: main thread is not in main loop RuntimeError:主线程不在主循环中-绘制两个图 - RuntimeError: main thread is not in main loop-Plotting in two figures 运行时错误:主线程不在主循环中使用带有 Django 的 Matplotlib - RuntimeError: main thread is not in main loop using Matplotlib with Django 调试 Tkinter 代码给出“RuntimeError:主线程不在主循环中” - Debugging Tkinter code gives "RuntimeError: main thread is not in main loop" RuntimeError:在 Timer 上设置 y 坐标时,主线程不在主循环中 - RuntimeError: main thread is not in main loop when setting y coordinate on Timer RuntimeError:使用tkinter.simpledialog时主线程不在主循环中 - RuntimeError: main thread is not in main loop while using tkinter.simpledialog 主线程不在主循环中 - Main thread is not in main loop
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM