如何处理tkinter mainloop中的错误? [英] How to handle errors in 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以显示下载进度(例如正在下载客户端5之17")
- 用户关闭窗口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
我一般建议阅读
- http://www.tkdocs.com/tutorial/index.html
- http://effbot.org/tkinterbook/tkinter-hello-tkinter.htm
- http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html
,针对您在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屋!