--- /dev/null
+import os
+import sys
+import threading
+
+import tkinter as tk
+from tkinter import messagebox
+from tkinter.font import Font
+
+
+class ExceptionDialog(tk.Toplevel):
+ def __init__(self, parent, txt, *args, **kwargs):
+ super().__init__(parent, *args, **kwargs);
+
+ self.title("Unhandled Exception");
+ self.attributes("-topmost", True);
+ self.wm_protocol("WM_DELETE_WINDOW", self.destroy)
+
+ sb = tk.Scrollbar(self);
+ sb.pack(side='right', fill='y')
+
+ te = tk.Text(self);
+ te.insert('end', txt);
+ te.pack(side='top', fill='both', expand=True)
+
+ te['yscrollcommand'] = sb.set
+ sb['command'] = te.yview
+
+ quit_btn = tk.Button(self, text="Quit",
+ command=self.destroy,
+ padx=5, pady=5)
+ quit_btn.pack(side='right')
import time
+import traceback
import datetime
import os
import subprocess
+import sys
+import _thread
import tkinter as tk
+from tkinter import messagebox
from tkinter.font import Font
import urllib3
import pyttsx3
+from .exception_dialog import ExceptionDialog
+
class QueueModel(object):
def __init__(self, config, *args, **kwargs):
self._cfg = config;
return result;
- def thread(self, tk_parent):
+ def thread(self, tk_parent, root):
+ """Wraps the original thread with exception handling"""
+ try:
+ self._thread(tk_parent);
+ except Exception as e:
+ err = traceback.format_exception(e);
+ if root:
+ tl = ExceptionDialog(root, "\n".join(err))
+ root.wait_window(tl);
+ else:
+ messagebox.showerror('Unhandled Exception in Polling Thread',
+ "\n".join(err) + ("\n\n"
+ "The application will now quit."));
+ print("Crashing application\n" + "\n".join(err), file=sys.stderr);
+ _thread.interrupt_main();
+
+ def _thread(self, tk_parent):
n_students = 0
cur_students = [];
self.build_elements(cur_students, tk_parent);
import os
+import sys
import threading
import tkinter as tk
+from tkinter import messagebox
from tkinter.font import Font
from .model import QueueModel
+from .exception_dialog import ExceptionDialog
+
from PIL import ImageTk, Image
fg=self._cnf.style.title__fgcolor);
self._title.pack(side='top', anchor='n', fill='x');
- self._frame = StudentCheckoffFrame(self, self._cnf);
+ self._frame = StudentCheckoffFrame(self, self._cnf, root=parent);
self._frame.pack(side='right', fill="both");
self._frame = TAPictureFrame(self, self._cnf);
self._frame.pack(side='top', fill='both', expand=1);
class StudentCheckoffFrame(tk.Frame):
- def __init__(self, parent, config, *args, **kwargs):
+ def __init__(self, parent, config, *args, root=None, **kwargs):
super().__init__(parent, *args, **kwargs);
self._cnf = config;
self._actualframe.pack(side='top', fill='both', expand=1);
t = threading.Thread(target=self._model.thread,
- args=(self._actualframe,),
+ args=(self._actualframe, root),
daemon=True)
t.start()
def fullscreen(self):
self.attributes("-fullscreen", True);
+
+ def report_callback_exception(self, *args):
+ err = traceback.format_exception(*args);
+ tl = ExceptionDialog(self, "\n".join(err))
+ self.wait_window(tl);
+ self.destroy();
+ print("Exiting application\n" + err, file=sys.stderr);
+ exit();