简体   繁体   English

如何向 tkinter 消息框添加“显示详细信息”按钮?

[英]How can I add a "show details" button to a tkinter messagebox?

I have a Python script which uses tkinter.messagebox to display an error message with traceback details if an unexpected exception occurs.我有一个 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())

标准 tkinter 错误

Displaying tracebacks this way has a few drawbacks.以这种方式显示回溯有一些缺点。

Instead of displaying error details by default, I would like to add a "show details" button which would display more information in a read-only text field.我不想默认显示错误详细信息,而是想添加一个“显示详细信息”按钮,该按钮将在只读文本字段中显示更多信息。

“除以零”的详细错误

How can I add a "show details" button to a tkinter messagebox?如何向 tkinter 消息框添加“显示详细信息”按钮?

I would use a Toplevel() window to build my own customer error box.我会使用Toplevel()窗口来构建我自己的客户错误框。

I think using ttk buttons here would be a good idea and with a combination of frames and weights we can get the window to look decent enough.我认为在这里使用ttk按钮是个好主意,结合框架和重量,我们可以让窗口看起来足够体面。

Keeping the window from being resized by the user I also had to set up a way to toggle the details textbox.为了防止用户调整窗口大小,我还必须设置一种方法来切换详细信息文本框。 With a tracking variable and the use of a if/else statement that was easy enough to set up.使用跟踪变量和使用 if/else 语句很容易设置。

Finally, we can disable the textbox with .config(state="disabled")最后,我们可以使用.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()

Results:结果:

在此处输入图像描述

在此处输入图像描述

Now with resizing:D现在调整大小:D

在此处输入图像描述

Update:更新:

In response to your statement below:回应您的以下声明:

The error window will not display if a Tk instance hasn't been initialized first.如果没有先初始化 Tk 实例,则不会显示错误窗口。

If we set up the class as its own Tk() instance it can be used as a stand alone error pop-up.如果我们将类设置为它自己的Tk()实例,它可以用作独立的错误弹出窗口。 I have also added some alignment changes and some resizing control to make this class a bit more conformative to the standard error messages you mention in the comments.我还添加了一些对齐更改和一些调整大小的控件,以使此类更符合您在评论中提到的标准错误消息。

See below code.请参阅下面的代码。

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

Results:结果:

在此处输入图像描述

在此处输入图像描述

You can add an image as well using canvas with the type of error image you want.您也可以使用带有所需错误图像类型的画布添加图像。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM