1 from tkinter import * 2 3 4 class WindowList: 5 6 def __init__(self): 7 self.dict = {} 8 self.callbacks = [] 9 10 def add(self, window): 11 window.after_idle(self.call_callbacks) 12 self.dict[str(window)] = window 13 14 def delete(self, window): 15 try: 16 del self.dict[str(window)] 17 except KeyError: 18 # Sometimes, destroy() is called twice 19 pass 20 self.call_callbacks() 21 22 def add_windows_to_menu(self, menu): 23 list = [] 24 for key in self.dict: 25 window = self.dict[key] 26 try: 27 title = window.get_title() 28 except TclError: 29 continue 30 list.append((title, key, window)) 31 list.sort() 32 for title, key, window in list: 33 menu.add_command(label=title, command=window.wakeup) 34 35 def register_callback(self, callback): 36 self.callbacks.append(callback) 37 38 def unregister_callback(self, callback): 39 try: 40 self.callbacks.remove(callback) 41 except ValueError: 42 pass 43 44 def call_callbacks(self): 45 for callback in self.callbacks: 46 try: 47 callback() 48 except: 49 t, v, tb = sys.exc_info() 50 print("warning: callback failed in WindowList", t, ":", v) 51 52 53 registry = WindowList() 54 55 add_windows_to_menu = registry.add_windows_to_menu 56 register_callback = registry.register_callback 57 unregister_callback = registry.unregister_callback 58 59 60 class ListedToplevel(Toplevel): 61 62 def __init__(self, master, **kw): 63 Toplevel.__init__(self, master, kw) 64 registry.add(self) 65 self.focused_widget = self 66 67 def destroy(self): 68 registry.delete(self) 69 Toplevel.destroy(self) 70 # If this is Idle's last window then quit the mainloop 71 # (Needed for clean exit on Windows 98) 72 if not registry.dict: 73 self.quit() 74 75 def update_windowlist_registry(self, window): 76 registry.call_callbacks() 77 78 def get_title(self): 79 # Subclass can override 80 return self.wm_title() 81 82 def wakeup(self): 83 try: 84 if self.wm_state() == "iconic": 85 self.wm_withdraw() 86 self.wm_deiconify() 87 self.tkraise() 88 self.focused_widget.focus_set() 89 except TclError: 90 # This can happen when the window menu was torn off. 91 # Simply ignore it. 92 pass 93