如何在tkinter中让静默异常变得显响?

28 投票
5 回答
10451 浏览
提问于 2025-04-16 10:27

如果我在终端运行下面的代码,我会在终端看到一个很有帮助的错误信息:

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 个回答

1

为了让@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)

3

首先,跟进一下:就在今天,关于 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

还需要更多的工作来确保弹出窗口在需要之前是隐藏的,然后再让它显示出来。

41

这里有一个叫做 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

撰写回答