如何在tkinter中让静默异常变得显响?
如果我在终端运行下面的代码,我会在终端看到一个很有帮助的错误信息:
import Tkinter as tk
master = tk.Tk()
def callback():
raise UserWarning("Exception!")
b = tk.Button(master, text="This will raise an exception", command=callback)
b.pack()
tk.mainloop()
但是,如果我不通过终端运行它(比如说,双击一个图标),错误信息就不会显示了。
在我更复杂的Tkinter应用程序中,我喜欢它的界面有点抗崩溃的能力。但我不喜欢的是,用户很难给我反馈,来帮助我修复那些意外出现的问题。
我该怎么处理这个问题呢?在Tkinter应用中,有没有标准的方法来显示错误信息或者其他相关信息?我希望能找到一种比到处放try/except更优雅的解决方案。
补充说明:Jochen Ritzel在下面给出了一个很好的答案,提到可以弹出一个警告框,并且提到可以把它附加到一个类上。为了让这个更清楚:
import Tkinter as tk
import traceback, tkMessageBox
class App:
def __init__(self, master):
master.report_callback_exception = self.report_callback_exception
self.frame = tk.Frame(master)
self.frame.pack()
b = tk.Button(
self.frame, text="This will cause an exception",
command=self.cause_exception)
b.pack()
def cause_exception(self):
a = []
a.a = 0 #A traceback makes this easy to catch and fix
def report_callback_exception(self, *args):
err = traceback.format_exception(*args)
tkMessageBox.showerror('Exception', err)
root = tk.Tk()
app = App(root)
root.mainloop()
我还有一个疑问:Jochen提到在不同的界面中可以有不同的错误报告函数。我还不太明白该怎么做。这一点明显吗?
5 个回答
为了让@Jochen Ritzel的回答更有价值,你可以在程序一开始就使用 try except
来捕捉Python的错误。
比如说,如果你想检测循环中出现的 index out of range
(索引超出范围)错误,你可以这样做:
# Note import files before the try statement
from tkinter import *
from tkinter import messagebox
import sys,traceback
def show_error(slef, *args):
err = traceback.format_exception(*args)
messagebox.showerror('Exception',err)
try:
root=Tk()
Tk.report_callback_exception = show_error
a=[1,2,3]
for i in range(10):
print(a[i])
exec(input()) # Just used to throw error
a=Button(text='s',command=lambda: print(8/0)) # Just used to throw error
a.pack()
root.mainloop()
except BaseException as e:
messagebox.showerror('Exception',e)
首先,跟进一下:就在今天,关于 tkinter.Tk.report_callback_exception
的文档更新在 CPython 跟踪器 上发布,明确表示 Jochen 的解决方案 是被认可的。这个更新主要是为了防止在 Windows 上用 pythonw 运行时,tk 在回调异常时崩溃。
其次:这里是一个简单的解决方案开头,目的是让 stderr
在没有控制台的情况下也能工作(这其实应该是一个单独的问题)。
import sys, tkinter
root = tkinter.Tk()
class Stderr(tkinter.Toplevel):
def __init__(self):
self.txt = tkinter.Text(root)
self.txt.pack()
def write(self, s):
self.txt.insert('insert', s)
sys.stderr = Stderr()
1/0 # traceback appears in window
还需要更多的工作来确保弹出窗口在需要之前是隐藏的,然后再让它显示出来。
这里有一个叫做 report_callback_exception
的东西可以用来处理这个问题:
import traceback
import tkMessageBox # py3: import tkinter.messagebox as tkMessageBox
# You would normally put that on the App class
def show_error(self, *args):
err = traceback.format_exception(*args)
tkMessageBox.showerror('Exception',err)
# but this works too
tk.Tk.report_callback_exception = show_error
如果你没有使用 import Tkinter as tk
这行代码,那就请先加上这行:
Tkinter.Tk.report_callback_exception = show_error