如何处理tkinter mainloop中的错误? [英] How to handle errors in tkinter mainloop?

查看:92
本文介绍了如何处理tkinter mainloop中的错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a python program which is scraping web data for a client. tkinter is used for the interface. Outline is:

  1. 窗口1使用户可以选择要刮擦的信息.
  2. 窗口1关闭
  3. 为刮板启动了单独的线程.该线程将依次产生更多线程,以允许一次下载多个页面.
  4. 打开窗口2以显示下载进度(例如正在下载客户端5之17")
  5. 用户关闭窗口2以结束程序.

该程序将在前几百页上工作,但随后它会吐出错误消息:

The program will work for the first few hundred pages, but then it starts spitting out the error message:

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>>

多次,直到所有线程都已停止.不知道是什么原因导致此错误.实际的代码是:

multiple times until all the threads have been stopped. No idea what could be causing this error. The actual code is:

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()

scraper程序(本身运行良好)使用打印语句来获取用户反馈.我没有重写所有内容,而是将stdout指向了一个队列.主线程使用之后"功能每秒检查一次队列.如果其中有任何内容,它将被打印到窗口上的文本"小部件中.

The scraper program (which works fine on its own) uses print statements for user feedback. Rather than re-write everything, I just pointed stdout to a queue. The main thread uses the "after" function to check on the queue a few times a second. If there is anything in it then it gets printed to the Text widget on the window.

我已经在代码中的几乎所有地方都放置了try/catch,但是他们没有发现任何问题.我确信问题出在主循环本身,但我找不到任何有关如何在其中添加新内容的最新信息.任何帮助将不胜感激.

I've put try/catch just about everywhere in the code, but they haven't caught a thing. I'm convinced the problem is in the mainloop itself, but I can't find any up to date information for how to stick something new in it. Any help would be greatly appreciated.

推荐答案

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

To handle tkinter errors you do the following

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

但是,在您的情况下,请不要这样做.仅在希望在生产期间隐藏来自用户的错误消息的情况下,才应该这样做.如上文所述,您遇到了一个noo问题.要生成多个窗口,可以使用 tkinter.Toplevel

But in your case please do not do this. This should only ever be done in the case of wanting to hide error messages from your users in production time. As commented above you have a nono's going on. To spawn multiple windows you can use tkinter.Toplevel

我一般建议阅读

,针对您在tkinter中出现的特定线程问题,本博客文章对此进行了介绍.基本上,您需要让tkinter mainloop阻塞程序的主线程,然后使用来自其他线程的after调用来运行mainloop中的其他代码.

and for your specific problem of threading in tkinter this blog post nails it. Basically you need to have the tkinter mainloop blocking the programs main thread, then use after calls from other threads to run other code in the mainloop.

这篇关于如何处理tkinter mainloop中的错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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