How can I add a "show details" button to a tkinter messagebox?
I would use a Toplevel()
window to build my own customer error box.
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.
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.
Finally, we can disable the textbox with .config(state="disabled")
import tkinter as tkimport tkinter.ttk as ttkimport tracebackclass 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 = Trueif __name__ == '__main__': App = MyApp().mainloop()
Results:
Now with resizing :D
Update:
In response to your statement below:
The error window will not display if a Tk instance hasn't been initialized first.
If we set up the class as its own Tk()
instance it can be used as a stand alone error pop-up. 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 tkimport tkinter.ttk as ttkclass 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.