如何捕获tkinter的mainloop运行过程中抛出的异常
Tkinter mainloop 异常捕获问题解答
异常未被外层try/except捕获的原因
- Tkinter的
mainloop是持续运行的内部事件循环,所有按钮点击这类用户触发的回调函数,都是在mainloop内部由Tkinter自带的CallWrapper工具类包裹后执行的 - 回调中抛出的异常会被
CallWrapper内部默认的异常处理逻辑拦截,不会向上冒泡到mainloop的调用位置,因此外层包裹的try/except完全接收不到这类异常 - 你观察到
mainloop之后的print语句不会执行,是因为mainloop本身是阻塞运行的,只有窗口关闭、循环结束后才会执行后续代码,异常抛出不会终止mainloop的运行,自然也不会把异常抛到外层。
异常处理方案
你可以通过替换Tkinter内置的CallWrapper类,实现全局统一捕获回调函数中的异常,操作如下:
在导入Tkinter相关模块后,新增自定义的异常处理包装类,替换默认的tkinter.CallWrapper,你可以在类的__call__方法中添加自己的异常捕获逻辑,修改后的完整代码如下:
from tkinter import Tk, Button import tkinter # 自定义异常处理包装类 class TkExceptionHandler: 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) # 这里可以根据需求捕获对应异常,或者用Exception捕获所有异常 except AttributeError as e: print("Error caught", e) # 替换Tkinter默认的回调包装类 tkinter.CallWrapper = TkExceptionHandler class Example: def __init__(self, root): Button(root, text="Throw Error", command=self.throwError).pack(padx=30, pady=30) def throwError(self, **args): raise AttributeError("Example Error") if __name__ == "__main__": root = Tk() Example(root) root.mainloop()
运行上述代码后,点击按钮抛出的AttributeError就会被自定义类中的except逻辑捕获。
内容的提问来源于stack exchange,提问作者TimH
相关产品推荐
相关产品推荐

