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