如何将 "show details" 按钮添加到 tkinter 消息框?
How can I add a "show details" button to a tkinter messagebox?
我有一个 Python 脚本,它使用 tkinter.messagebox
在发生意外异常时显示带有回溯详细信息的错误消息。
import tkinter.messagebox as tm
import traceback
try:
1/0
except Exception as error:
tm.showerror(title="Error",
message="An error has occurred: '" + str(error) + "'.",
detail=traceback.format_exc())
以这种方式显示回溯有一些缺点。
- 回溯详细信息aren't helpful for the average user。
- 测试人员无法轻松地select并从消息框中复制文本
- 复杂的错误可能 large tracebacks 跨越几十行。
我想添加一个 "show details" 按钮来在只读文本字段中显示更多信息,而不是默认显示错误详细信息。
如何将 "show details" 按钮添加到 tkinter 消息框?
我会使用 Toplevel()
window 来构建我自己的客户错误框。
我认为在这里使用 ttk
按钮是个好主意,结合框架和权重,我们可以使 window 看起来足够体面。
为了防止 window 被用户调整大小,我还必须设置一种方法来切换详细信息文本框。使用跟踪变量和使用易于设置的 if/else 语句。
最后,我们可以使用 .config(state="disabled")
禁用文本框
import tkinter as tk
import tkinter.ttk as ttk
import traceback
class MyApp(tk.Tk):
def __init__(self):
super().__init__()
tk.Button(self, text='test error', command=self.run_bad_math).pack()
@staticmethod
def run_bad_math():
try:
1/0
except Exception as error:
title = 'Traceback Error'
message = "An error has occurred: '{}'.".format(error)
detail = traceback.format_exc()
TopErrorWindow(title, message, detail)
class TopErrorWindow(tk.Toplevel):
def __init__(self, title, message, detail):
tk.Toplevel.__init__(self)
self.details_expanded = False
self.title(title)
self.geometry('350x75')
self.minsize(350, 75)
self.maxsize(425, 250)
self.rowconfigure(0, weight=0)
self.rowconfigure(1, weight=1)
self.columnconfigure(0, weight=1)
button_frame = tk.Frame(self)
button_frame.grid(row=0, column=0, sticky='nsew')
button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
text_frame = tk.Frame(self)
text_frame.grid(row=1, column=0, padx=(7, 7), pady=(7, 7), sticky='nsew')
text_frame.rowconfigure(0, weight=1)
text_frame.columnconfigure(0, weight=1)
ttk.Label(button_frame, text=message).grid(row=0, column=0, columnspan=2, pady=(7, 7))
ttk.Button(button_frame, text='OK', command=self.destroy).grid(row=1, column=0, sticky='e')
ttk.Button(button_frame, text='Details', command=self.toggle_details).grid(row=1, column=1, sticky='w')
self.textbox = tk.Text(text_frame, height=6)
self.textbox.insert('1.0', detail)
self.textbox.config(state='disabled')
self.scrollb = tk.Scrollbar(text_frame, command=self.textbox.yview)
self.textbox.config(yscrollcommand=self.scrollb.set)
def toggle_details(self):
if self.details_expanded:
self.textbox.grid_forget()
self.scrollb.grid_forget()
self.geometry('350x75')
self.details_expanded = False
else:
self.textbox.grid(row=0, column=0, sticky='nsew')
self.scrollb.grid(row=0, column=1, sticky='nsew')
self.geometry('350x160')
self.details_expanded = True
if __name__ == '__main__':
App = MyApp().mainloop()
结果:
现在可以调整大小:D
更新:
回应您的以下声明:
The error window will not display if a Tk instance hasn't been initialized first.
如果我们将 class 设置为它自己的 Tk()
实例,它可以用作独立的错误弹出窗口。我还添加了一些对齐更改和一些调整大小的控件,以使此 class 更符合您在评论中提到的标准错误消息。
见下面的代码。
import tkinter as tk
import tkinter.ttk as ttk
class TopErrorWindow(tk.Tk):
def __init__(self, title, message, detail):
super().__init__()
self.details_expanded = False
self.title(title)
self.geometry('350x75')
self.minsize(350, 75)
self.maxsize(425, 250)
self.resizable(False, False)
self.rowconfigure(0, weight=0)
self.rowconfigure(1, weight=1)
self.columnconfigure(0, weight=1)
button_frame = tk.Frame(self)
button_frame.grid(row=0, column=0, sticky='nsew')
button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
text_frame = tk.Frame(self)
text_frame.grid(row=1, column=0, padx=(7, 7), pady=(7, 7), sticky='nsew')
text_frame.rowconfigure(0, weight=1)
text_frame.columnconfigure(0, weight=1)
ttk.Label(button_frame, text=message).grid(row=0, column=0, columnspan=3, pady=(7, 7), padx=(7, 7), sticky='w')
ttk.Button(button_frame, text='OK', command=self.destroy).grid(row=1, column=1, sticky='e')
ttk.Button(button_frame, text='Details',
command=self.toggle_details).grid(row=1, column=2, padx=(7, 7), sticky='e')
self.textbox = tk.Text(text_frame, height=6)
self.textbox.insert('1.0', detail)
self.textbox.config(state='disabled')
self.scrollb = tk.Scrollbar(text_frame, command=self.textbox.yview)
self.textbox.config(yscrollcommand=self.scrollb.set)
self.mainloop()
def toggle_details(self):
if self.details_expanded:
self.textbox.grid_forget()
self.scrollb.grid_forget()
self.resizable(False, False)
self.geometry('350x75')
self.details_expanded = False
else:
self.textbox.grid(row=0, column=0, sticky='nsew')
self.scrollb.grid(row=0, column=1, sticky='nsew')
self.resizable(True, True)
self.geometry('350x160')
self.details_expanded = True
结果:
您也可以使用 canvas 添加您想要的错误图像类型的图像。
我有一个 Python 脚本,它使用 tkinter.messagebox
在发生意外异常时显示带有回溯详细信息的错误消息。
import tkinter.messagebox as tm
import traceback
try:
1/0
except Exception as error:
tm.showerror(title="Error",
message="An error has occurred: '" + str(error) + "'.",
detail=traceback.format_exc())
以这种方式显示回溯有一些缺点。
- 回溯详细信息aren't helpful for the average user。
- 测试人员无法轻松地select并从消息框中复制文本
- 复杂的错误可能 large tracebacks 跨越几十行。
我想添加一个 "show details" 按钮来在只读文本字段中显示更多信息,而不是默认显示错误详细信息。
如何将 "show details" 按钮添加到 tkinter 消息框?
我会使用 Toplevel()
window 来构建我自己的客户错误框。
我认为在这里使用 ttk
按钮是个好主意,结合框架和权重,我们可以使 window 看起来足够体面。
为了防止 window 被用户调整大小,我还必须设置一种方法来切换详细信息文本框。使用跟踪变量和使用易于设置的 if/else 语句。
最后,我们可以使用 .config(state="disabled")
import tkinter as tk
import tkinter.ttk as ttk
import traceback
class MyApp(tk.Tk):
def __init__(self):
super().__init__()
tk.Button(self, text='test error', command=self.run_bad_math).pack()
@staticmethod
def run_bad_math():
try:
1/0
except Exception as error:
title = 'Traceback Error'
message = "An error has occurred: '{}'.".format(error)
detail = traceback.format_exc()
TopErrorWindow(title, message, detail)
class TopErrorWindow(tk.Toplevel):
def __init__(self, title, message, detail):
tk.Toplevel.__init__(self)
self.details_expanded = False
self.title(title)
self.geometry('350x75')
self.minsize(350, 75)
self.maxsize(425, 250)
self.rowconfigure(0, weight=0)
self.rowconfigure(1, weight=1)
self.columnconfigure(0, weight=1)
button_frame = tk.Frame(self)
button_frame.grid(row=0, column=0, sticky='nsew')
button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
text_frame = tk.Frame(self)
text_frame.grid(row=1, column=0, padx=(7, 7), pady=(7, 7), sticky='nsew')
text_frame.rowconfigure(0, weight=1)
text_frame.columnconfigure(0, weight=1)
ttk.Label(button_frame, text=message).grid(row=0, column=0, columnspan=2, pady=(7, 7))
ttk.Button(button_frame, text='OK', command=self.destroy).grid(row=1, column=0, sticky='e')
ttk.Button(button_frame, text='Details', command=self.toggle_details).grid(row=1, column=1, sticky='w')
self.textbox = tk.Text(text_frame, height=6)
self.textbox.insert('1.0', detail)
self.textbox.config(state='disabled')
self.scrollb = tk.Scrollbar(text_frame, command=self.textbox.yview)
self.textbox.config(yscrollcommand=self.scrollb.set)
def toggle_details(self):
if self.details_expanded:
self.textbox.grid_forget()
self.scrollb.grid_forget()
self.geometry('350x75')
self.details_expanded = False
else:
self.textbox.grid(row=0, column=0, sticky='nsew')
self.scrollb.grid(row=0, column=1, sticky='nsew')
self.geometry('350x160')
self.details_expanded = True
if __name__ == '__main__':
App = MyApp().mainloop()
结果:
现在可以调整大小:D
更新:
回应您的以下声明:
The error window will not display if a Tk instance hasn't been initialized first.
如果我们将 class 设置为它自己的 Tk()
实例,它可以用作独立的错误弹出窗口。我还添加了一些对齐更改和一些调整大小的控件,以使此 class 更符合您在评论中提到的标准错误消息。
见下面的代码。
import tkinter as tk
import tkinter.ttk as ttk
class TopErrorWindow(tk.Tk):
def __init__(self, title, message, detail):
super().__init__()
self.details_expanded = False
self.title(title)
self.geometry('350x75')
self.minsize(350, 75)
self.maxsize(425, 250)
self.resizable(False, False)
self.rowconfigure(0, weight=0)
self.rowconfigure(1, weight=1)
self.columnconfigure(0, weight=1)
button_frame = tk.Frame(self)
button_frame.grid(row=0, column=0, sticky='nsew')
button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
text_frame = tk.Frame(self)
text_frame.grid(row=1, column=0, padx=(7, 7), pady=(7, 7), sticky='nsew')
text_frame.rowconfigure(0, weight=1)
text_frame.columnconfigure(0, weight=1)
ttk.Label(button_frame, text=message).grid(row=0, column=0, columnspan=3, pady=(7, 7), padx=(7, 7), sticky='w')
ttk.Button(button_frame, text='OK', command=self.destroy).grid(row=1, column=1, sticky='e')
ttk.Button(button_frame, text='Details',
command=self.toggle_details).grid(row=1, column=2, padx=(7, 7), sticky='e')
self.textbox = tk.Text(text_frame, height=6)
self.textbox.insert('1.0', detail)
self.textbox.config(state='disabled')
self.scrollb = tk.Scrollbar(text_frame, command=self.textbox.yview)
self.textbox.config(yscrollcommand=self.scrollb.set)
self.mainloop()
def toggle_details(self):
if self.details_expanded:
self.textbox.grid_forget()
self.scrollb.grid_forget()
self.resizable(False, False)
self.geometry('350x75')
self.details_expanded = False
else:
self.textbox.grid(row=0, column=0, sticky='nsew')
self.scrollb.grid(row=0, column=1, sticky='nsew')
self.resizable(True, True)
self.geometry('350x160')
self.details_expanded = True
结果:
您也可以使用 canvas 添加您想要的错误图像类型的图像。