如何处理tkinter mainloop中的错误?

时间:2016-02-14 04:12:21

标签: python multithreading exception tkinter

我有一个python程序,它正在为客户端抓取Web数据。 tkinter用于接口。大纲是:

  1. 窗口1允许用户选择要刮取的信息。
  2. 窗口1关闭
  3. 为刮刀启动单独的线程。该线程将产生更多线程,以允许一次下载多个页面。
  4. 窗口2打开以显示下载进度(例如“下载客户端5 of 17”)
  5. 用户关闭窗口2以结束程序。
  6. 该程序将适用于前几百页,但随后它开始吐出错误消息:

    Traceback (most recent call last):
    File "C:\Users\Me\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 248, in __del__
    if self._tk.getboolean(self._tk.call("info", "exists", self._name)):
    RuntimeError: main thread is not in main loop
    Exception ignored in: <bound method Variable.__del__ of <tkinter.IntVar object at 0x03245510>>
    

    多次,直到所有线程都停止。不知道是什么导致了这个错误。实际代码是:

    import scraper, threading
    import tkinter as tk
    from queue import Queue
    
    outputQueue = Queue()
    
    class OutputRedirect(object):
        def __init__():
            super().__init__()
    
        def write(self, string):
            outputQueue.put(string)
    
    def getInformation():
        stdout = sys.stdout
        sys.stdout = OutputRedirect()
    
        scraper.startThreads()
        scraper.startPulling() 
    
        sys.stdout = stdout
    
    def updateTextField(window, root):
    
        if not outputQueue.empty():
            string = outputQueue.get()
            window.textArea.insert("insert", string)         
            outputQueue.task_done()
    
        root.after(1, updateTextField, window, root)
    
    '''widget/window definitions - not important'''
    
    guiInfo = {"stuff1": [], "stuff2": []}
    
    root = tk.Tk()
    window1 = Window1(root, guiInfo)
    window1.mainloop()
    
    pullThread = threading.Thread(target=pullClaims,
                                  args=(list(guiInfo["stuff1"]),
                                  list(guiInfo["stuff2"])), daemon=True)
    pullThread.start()
    
    root = tk.Tk()
    window2 = Window2(root)
    root.after(0, updateTextField, window2, root)
    window2.mainloop()
    

    刮刀程序(单独工作正常)使用print语句进行用户反馈。我只是将stdout指向队列,而不是重写所有内容。主线程使用“after”函数每秒检查一次队列几次。如果其中有任何内容,则会将其打印到窗口上的“文本”小部件中。

    我在代码中的任何地方放置了try / catch,但它们没有抓到任何东西。我确信问题出现在主循环中,但是我找不到任何关于如何在其中添加新内容的最新信息。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

要处理tkinter错误,请执行以下操作

class TkErrorCatcher:

    '''
    In some cases tkinter will only print the traceback.
    Enables the program to catch tkinter errors normally

    To use
    import tkinter
    tkinter.CallWrapper = TkErrorCatcher
    '''

    def __init__(self, func, subst, widget):
        self.func = func
        self.subst = subst
        self.widget = widget

    def __call__(self, *args):
        try:
            if self.subst:
                args = self.subst(*args)
            return self.func(*args)
        except SystemExit as msg:
            raise SystemExit(msg)
        except Exception as err:
            raise err

import tkinter
tkinter.CallWrapper = TkErrorCatcher

但在你的情况下请不要这样做。只有在想要在生产时隐藏用户的错误消息时才应该这样做。如上所述,你有一个nono's正在进行。 要生成多个窗口,您可以使用tkinter.Toplevel

我建议一般阅读

并且针对您在tkinter中的特定线程问题,这个博客文章指出了它。基本上你需要让tkinter mainloop阻塞程序主线程,然后在其他线程的调用之后使用来运行mainloop中的其他代码。