I have written an application in Python Tkinter. I recently noticed that for one of the operation, it sometimes closes (without giving any error) if that operation failed. I have written a small program to illustrate the problem :-
import os
from Tkinter import *
def copydir():
src = "D:\\a\\x\\y"
dest = "D:\\a\\x\\z"
os.rename(src,dest)
master = Tk()
def callback():
global master
master.after(1, callback)
copydir()
print "click!"
b = Button(master, text="OK", command=copydir)
b.pack()
master.after(100, callback)
mainloop()
To reproduce the problem, open the folder which it will rename in “ms command prompt” such that renaming it will throw exception from Tkinter code.
My original code is using threading and is performing other tasks as well, so I have tried to make the operations in this test script as similar as possible.
Now, if I run this code by double clicking it, then program simply closes without throwing any error. But If I had been running this script from console, then exception messages are dumped on the console and atleast I got to know , something is wrong.
I can fix this code by using try/catch in the code where it tried to rename but I want to inform user about this failure as well. So I just want to know what coding approaches should be followed while writing Tkinter App's and I want to know:-
1) Can I make my script dump some stack trace in a file whenever user ran this by double clicking on it. By this atleast, I would know something is wrong and fix it.
2) Can I prevent the tkinter app to exit on such error and throw any exception in some TK dialog.
Thanks for help!!
In Python, we catch exceptions and handle them using try and except code blocks. The try clause contains the code that can raise an exception, while the except clause contains the code lines that handle the exception.
Uncaught exceptions in GUI applications In practical terms, an exception to this is in GUI applications (including Swing applications), where an uncaught exceptions occurs in the event dispatch thread. This means in event handlers, such as the actionPerformed() method of an ActionListener.
Tkinter is a Python package which comes with many functions and methods that can be used to create an application. In order to create a tkinter application, we generally create an instance of tkinter frame, i.e., Tk(). It helps to display the root window and manages all the other components of the tkinter application.
I see you have a non-object oriented example, so I'll show two variants to solve the problem of exception-catching.
The key is in the in the tkinter\__init__.py
file. One can see that there is a documented method report_callback_exception
of Tk
class. Here is its description:
report_callback_exception()
Report callback exception on sys.stderr.
Applications may want to override this internal function, and should when sys.stderr is None.
So as we see it it is supposed to override this method, lets do it!
Non-object oriented solution
import tkinter as tk
from tkinter.messagebox import showerror
if __name__ == '__main__':
def bad():
raise Exception("I'm Bad!")
# any name as accepted but not signature
def report_callback_exception(self, exc, val, tb):
showerror("Error", message=str(val))
tk.Tk.report_callback_exception = report_callback_exception
# now method is overridden
app = tk.Tk()
tk.Button(master=app, text="bad", command=bad).pack()
app.mainloop()
Object oriented solution
import tkinter as tk
from tkinter.messagebox import showerror
class Bad(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# or tk.Tk.__init__(*args, **kwargs)
def bad():
raise Exception("I'm Bad!")
tk.Button(self, text="bad", command=bad).pack()
def report_callback_exception(self, exc, val, tb):
showerror("Error", message=str(val))
if __name__ == '__main__':
app = Bad()
app.mainloop()
The result
My environment:
Python 3.5.1 |Anaconda 2.4.1 (64-bit)| (default, Dec 7 2015, 15:00:12) [MSC
v.1900 64 bit (AMD64)] on win32
tkinter.TkVersion
8.6
tkinter.TclVersion
8.6
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With